• 2019 The Preliminary Contest for ICPC China Nanchang National Invitational


    传送门:

    Problem A

    温暖的签到题,打个表就行了。

    吐槽一下:出题人并没有说用什么格式输出,害得我输出一行怒得一pe

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        cout<<6<<endl;
        cout<<28<<endl;
        cout<<496<<endl;
        cout<<8128<<endl;
        cout<<33550336<<endl;
        return 0;
    }
    

    Problem B


    Problem C


    Problem D


    Problem E


    Problem F


    Problem G


    Problem H

    规律题,经过推倒发现答案为:3n243^{n-2}*4

    快速幂搞搞就万事了。

    #include <iostream>
    #include <cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    ll powm(ll x,ll n){
        ll res=1;
        while (n){
            if (n&1) res=res*x%mod;
            n>>=1;
            x=x*x%mod;
        }
        return res;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        ll n,ans=0;
        cin>>n;
        if (n==1) ans=1;
        else ans=powm(3,n-2)*4%mod;
        cout<<ans<<endl;
        return 0;
    }
    

    Problem I

    题意:

    给你一个长度为nn的序列,让你找到一个区间[l,r][l,r],使得i=lrai×mini=lraisum_{i=l}^{r}{a_i} imesmin_{i=l}^{r}{a_i}最大

    其中,106ai106-10^6le a_ile10^6

    分析:

    如果aia_i不能取负数,则是poj2796 ext{poj2796}的原题,我们用单调栈对每一个aia_i处理出以aia_i为最小值,最左/最右能扩展到的位置,之后直接贪心扫即可。

    而在这个题中,因为涉及负数×负数的情况,则我们不能直接累加某段区间的和。

    我们考虑用线段树去记录区间前缀和的最大值以及最小值。我们可以贪心的去思考,倘若当前的aia_i大于00,则显然是取区间[i,ar][i,a_r]中的最大值maxmax,以及区间[al,i][a_l,i]中的最小值minminmaxminmax-min即为以aia_i为最小值的最大区间和。同理,对于ai&lt;0a_i&lt;0的情况,我们只需尽量取区间[al,ar][a_l,a_r]中的最小区间和即可。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=500005;
    int a[maxn];
    long long sum[maxn];
    int n,m;
    struct node
    {
        int l,r;
        long long mx,add,mn;
    }tr[maxn*4];
    void push_up(int k){
        tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
        tr[k].mn=min(tr[k<<1].mn,tr[k<<1|1].mn);
    }
    void build(int k,int l,int r)
    {
        tr[k].l=l,tr[k].r=r;
        tr[k].add=0;
        if(l==r){
            tr[k].mx=sum[l];
            tr[k].mn=sum[l];
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        push_up(k);
    }
    void pushdown(int k)
    {
        if(tr[k].add!=0)
        {
            tr[k<<1].add+=tr[k].add;
            tr[k<<1].mx+=tr[k].add;
            tr[k<<1].mn+=tr[k].add;
            tr[k<<1|1].add+=tr[k].add;
            tr[k<<1|1].mx+=tr[k].add;
            tr[k<<1|1].mn+=tr[k].add;
            tr[k].add=0;
        }
    }
    void update(int k,int s,int t,int v)
    {
        int l=tr[k].l,r=tr[k].r;
        if(l>t||r<s) return;
        if(l>=s&&r<=t)
        {
            tr[k].mx+=v;
            tr[k].mn+=v;
            tr[k].add+=v;
            return;
        }
        pushdown(k);
        update(k<<1,s,t,v);
        update(k<<1|1,s,t,v);
        push_up(k);
    }
    long long query(int k,int s,int t)
    {
        int l=tr[k].l,r=tr[k].r;
        if(l>t||r<s) return 0;
        if(l>=s&&r<=t) return tr[k].mx;
        pushdown(k);
        return max(query(k<<1,s,t),query(k<<1|1,s,t));
    }
    long long query1(int k,int s,int t)
    {
        int l=tr[k].l,r=tr[k].r;
        if(l>t||r<s) return 0;
        if(l>=s&&r<=t) return tr[k].mn;
        pushdown(k);
        return min(query1(k<<1,s,t),query1(k<<1|1,s,t));
    }
    void read(int &ret){
        ret=0;
        char ch=getchar();
        int flag=1;
        while(ch>'9'||ch<'0'){if(ch=='-')flag=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){
            ret=ret*10+ch-'0';
            ch=getchar();
        }
        ret*=flag;
    }
    int L[maxn],R[maxn];
    long long ans1[maxn],ans2[maxn];
    int main()
    {
        //freopen("in.txt","r",stdin);
        read(n);
        //cin>>n;
        for(int i=1;i<=n;i++){
            read(a[i]);
            //cin>>a[i];
            sum[i]=sum[i-1]+a[i];
            L[i]=R[i]=i;
        }
        a[0]=a[n+1]=-0x3f3f3f3f;
        for(int i=1;i<=n;i++){
            while(a[i]<=a[L[i]-1])
                L[i]=L[L[i]-1];
        }
        for(int i=n;i>=1;i--){
            while(a[i]<=a[R[i]+1])
                R[i]=R[R[i]+1];
        }
        int r=1;
        a[0]=a[n+1]=0;
        build(1,1,n);
        for(int i=1;i<=n;i++){
            update(1,i,n,-a[i-1]);
            if(a[i]>=0)ans1[i]=query(1,i,R[i]);
            else ans1[i]=query1(1,i,R[i]);
        }
        for(int i=n;i;i--){sum[i]=sum[i+1]+a[i];}
        build(1,1,n);
        for(int i=n;i;i--){
            update(1,1,i,-a[i+1]);
            if(a[i]>=0)ans2[i]=query(1,L[i],i);
            else ans2[i]=query1(1,L[i],i);
        }
        long long mx=-0x3f3f3f3f3f3f3f3f;
        for(int i=1;i<=n;i++){
            mx=max(mx,(ans1[i]+ans2[i]-a[i])*a[i]);
        }
        printf("%lld
    ",mx);
        return 0;
    }
    

    Problem J

    题意:

    给你一棵有nn个节点的树,每条边上有个边权ww,现在有qq个询问,问你在节点uu到节点vv的路径中,有多少条边的边权是大于kk的。

    分析:

    考虑去二分答案。如果用二分去解的话,这个问题就转化为让你找到一个最小的tt,使得tt条边的权值都大于kk。则显然我们只需要求这段路径上的第tt大的路径的值,并判断第tt大的路径的值是否大于kk即可。

    因此我们要求的就是一个经典的树上路径第kk大的问题,因此我们可以用主席树去解决。

    总体的时间复杂度为:O(nlog2(n))mathcal{O}(nlog^2(n))

    代码:
    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 200010;
    const int M = MAXN * 40;
    int n,q,m,TOT;
    int a[MAXN], t[MAXN];
    int T[M], lson[M], rson[M], c[M];
    
    void Init_hash()
    {
        for(int i = 1; i <= n;i++)
            t[i] = a[i];
        sort(t+1,t+1+n);
        m = unique(t+1,t+n+1)-t-1;
    }
    int build(int l,int r)
    {
        int root = TOT++;
        c[root] = 0;
        if(l != r)
        {
            int mid = (l+r)>>1;
            lson[root] = build(l,mid);
            rson[root] = build(mid+1,r);
        }
        return root;
    }
    int Hash(int x)
    {
        return lower_bound(t+1,t+1+m,x) - t;
    }
    int update(int root,int pos,int val)
    {
        int newroot = TOT++, tmp = newroot;
        c[newroot] = c[root] + val;
        int l = 1, r = m;
        while( l < r)
        {
            int mid = (l+r)>>1;
            if(pos <= mid)
            {
                lson[newroot] = TOT++; rson[newroot] = rson[root];
                newroot = lson[newroot]; root = lson[root];
                r = mid;
            }
            else
            {
                rson[newroot] = TOT++; lson[newroot] = lson[root];
                newroot = rson[newroot]; root = rson[root];
                l = mid+1;
            }
            c[newroot] = c[root] + val;
        }
        return tmp;
    }
    int query(int left_root,int right_root,int LCA,int k)
    {
        int lca_root = T[LCA];
        int pos = Hash(a[LCA]);
        int l = 1, r = m;
        while(l < r)
        {
            int mid = (l+r)>>1;
            int tmp = c[lson[left_root]] + c[lson[right_root]] - 2*c[lson[lca_root]] + (pos >= l && pos <= mid);
            if(tmp >= k)
            {
                left_root = lson[left_root];
                right_root = lson[right_root];
                lca_root = lson[lca_root];
                r = mid;
            }
            else
            {
                k -= tmp;
                left_root = rson[left_root];
                right_root = rson[right_root];
                lca_root = rson[lca_root];
                l = mid + 1;
            }
        }
        return l;
    }
    
    int rmq[2*MAXN];
    struct ST
    {
        int mm[2*MAXN];
        int dp[2*MAXN][20];
        void init(int n)
        {
            mm[0] = -1;
            for(int i = 1;i <= n;i++)
            {
                mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
                dp[i][0] = i;
            }
            for(int j = 1; j <= mm[n];j++)
                for(int i = 1; i + (1<<j) - 1 <= n; i++)
                    dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
        int query(int a,int b)
        {
            if(a > b)swap(a,b);
            int k = mm[b-a+1];
            return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
        }
    };
    struct Edge
    {
        int to,next,val;
    };
    Edge edge[MAXN*2];
    int tot,head[MAXN];
    
    int F[MAXN*2];
    int P[MAXN];
    int cnt;
    
    ST st;
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int val)
    {
        edge[tot].to = v;
        edge[tot].next = head[u];
        edge[tot].val=val;
        head[u] = tot++;
    }
    void dfs(int u,int pre,int dep)
    {
        F[++cnt] = u;
        rmq[cnt] = dep;
        P[u] = cnt;
        for(int i = head[u];i != -1;i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == pre)continue;
            dfs(v,u,dep+1);
            F[++cnt] = u;
            rmq[cnt] = dep;
        }
    }
    void LCA_init(int root,int node_num)
    {
        cnt = 0;
        dfs(root,root,0);
        st.init(2*node_num-1);
    }
    int query_lca(int u,int v)
    {
        return F[st.query(P[u],P[v])];
    }
    
    void dfs_build(int u,int pre)
    {
        int pos = Hash(a[u]);
        T[u] = update(T[pre],pos,1);
        for(int i = head[u]; i != -1;i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == pre)continue;
            dfs_build(v,u);
        }
    }
    bool check(int u,int v,int k,int val){
        if(t[query(T[u],T[v],query_lca(u,v),k)]>val) return 1;
        return 0;
    }
    int Find(int u,int v,int l,int r,int k){
        int ret;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(u,v,mid,k)){
                ret=mid;
                r=mid-1;
            }else l=mid+1;
        }
        if(a[query_lca(u,v)]<=k) ret-=1;
        return ret;
    }
    void dfs(int u,int fa){
        for(int i=head[u];~i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa) continue;
            a[to]=edge[i].val;
            dfs(to,u);
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d%d",&n,&q) == 2)
        {
    
            TOT = 0;
            int u,v,vv;
            a[1]=0x3f3f3f3f;
            init();
            for(int i = 1;i < n;i++)
            {
                scanf("%d%d%d",&u,&v,&vv);
                addedge(u,v,vv);
                addedge(v,u,vv);
            }
            dfs(1,-1);
            Init_hash();
            LCA_init(1,n);
            T[n+1] = build(1,m);
            dfs_build(1,n+1);
            int k;
            while(q--)
            {
                scanf("%d%d%d",&u,&v,&k);
                printf("%d
    ",Find(u,v,1,n,k)-1);
            }
            return 0;
        }
        return 0;
    }
    

    Problem K

    找规律+前缀亦或和

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    const int maxn=1e5+7;
    unsigned int a[maxn],b[maxn][4];
    namespace fastIO {
    #define BUF_SIZE 100000
        //fread -> read
        bool IOerror = 0;
        inline char nc() {
            static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
            if(p1 == pend) {
                p1 = buf;
                pend = buf + fread(buf, 1, BUF_SIZE, stdin);
                if(pend == p1) {
                    IOerror = 1;
                    return -1;
                }
            }
            return *p1++;
        }
        inline bool blank(char ch) {
            return ch == ' ' || ch == '
    ' || ch == '
    ' || ch == '	';
        }
        inline void read(int &x) {
            char ch;
            while(blank(ch = nc()));
            if(IOerror) return;
            for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
        }
        inline void read(unsigned int &x) {
            char ch;
            while(blank(ch = nc()));
            if(IOerror) return;
            for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
        }
    #undef BUF_SIZE
    };
    using namespace fastIO;
    int main(){
        int t;
        read(t);
        while (t--){
            int n,q,l,r;
            read(n);
            for (int i=0;i<n;i++) {
                read(a[i]);
                b[i][0]=b[i][1]=b[i][2]=b[i][3]=0;
            }
            int m=(n+3)/4+1;
            for (int i=0;i<n;i++)
                b[i/4+1][i%4]=a[i];
    //        for (int i=0;i<4;i++){
    //            for (int j=0;j<=m+1;j++) cout<<b[j][i]<<' ';cout<<endl;
    //        }
    
            for (int i=1;i<=m+1;i++) {
                for (int j=0;j<4;j++)
                    b[i][j]^=b[i-1][j];
            }
            read(q);
            while (q--){
                read(l);read(r);
                unsigned ans=0;
                int tmp=(r-l)%4;
                l--;r--;
                if (tmp==3) ans=0;
                else if (tmp==2) {
                    int ll=l+1,rr=r-1;
                    ans=b[rr/4+1][ll%4]^b[ll/4][ll%4];
                }else if (tmp==1){
                    int ll=l,rr=r-1;
                    ans=b[rr/4+1][ll%4]^b[ll/4][ll%4] ^b[(rr+1)/4+1][(ll+1)%4]^b[(ll+1)/4][(ll+1)%4];
                }else if (tmp==0){
                    int ll=l,rr=r;
                    ans=b[rr/4+1][ll%4]^b[ll/4][ll%4];
                }
                printf("%u
    ",ans);
            }
        }
        return 0;
    }
    

    Problem L


    Problem M

    题意:

    给你一个串strstr以及nn个串stristr_i,问你这nn个串stristr_i是否是串strstr的子序列。

    分析:

    直接暴力匹配显然会T,而又根据子序列的性质(下一个字符要匹配的字符cc必定是在原串离上一个匹配成果的位置pospos的最近的位置上),我们可以考虑对原串进行预处理。

    我们设f[i][j] ext{f[i][j]}为:在原串ii位置上,离字符jj最近的位置。我们可以用O(len)mathcal{O}(len)的时间预处理出来这个,而在我们进行nn个串的匹配时,我们不断在ff数组上去跳转即可。

    代码:
    #include <bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    char str[100005],p[1005];
    int f[100005][300];
    int len,n;
    void init(){
        for(int i=0;i<len;i++){
            int flag=str[i];
            for(int j=i;j>=0;j--){
                if(f[j][flag]!=-1) break;
                f[j][flag]=i;
            }
        }
    }
    int main()
    {
    //freopen("in.txt","r",stdin);
        scanf("%s",str);
        scanf("%d",&n);
        len=strlen(str);
        memset(f,-1,sizeof(f));
        init();
        while(n--){
            scanf("%s",p);
            int l=strlen(p);
            int cur=0;
            bool flag=0;
            for(int i=0;i<l;i++){
                if(f[cur][p[i]]==-1){
                    flag=1;
                    break;
                }
                cur=f[cur][p[i]]+1;
            }
            if(flag)puts("NO");
            else puts("YES");
        }
        return 0;
    }
    
  • 相关阅读:
    go 错误处理策略
    git merge
    oracle
    使用PHPExcel导入数据库,date数据的问题
    PhpWord使用
    ThinkPHP
    Memcache
    没用过docker就out了
    TCP三次挥手四次协议
    数据分析
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007144.html
Copyright © 2020-2023  润新知