• [4.6校内训练赛]


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    A.[cf577b]Modulo Sum

    给定n个数,问是否有一个子序列相加的和取余m为0  n<=10^6,m<=1000

    题解:很容易想到nmDP,(我写了暴力1950ms过了哈哈哈),另外m<n的时候肯定有可以整除m的,因为前缀和的余数最多只有m种。

    代码丑,其实就是暴力加了一句话.....nmDP大家都会,就不重写了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int b[1005],n,m,f[1005][1005],mark[1005];
    
    int main()
    {
        n=read();m=read();
        if(m<n)return 0*puts("YES");
        for(int i=1;i<=n;i++)b[read()%m]++;
        n=0;
        for(int i=0;i<m;i++)mark[i]=-1;
        for(int i=0;i<m;i++)
        { 
            if(!b[i]) continue;
            ++n;
            for(int j=0;j<m;j++)
                f[n][j]|=f[n-1][j];
            for(int k=1;k<=b[i];k++)
            {
                int th=k*i%m;
                if(mark[th]==i) break;mark[th]=i;
                f[n][th]=1;
                for(int j=0;j<m;j++) 
                    f[n][(th+j)%m]|=f[n-1][j];
        //        printf("%d
    ",th);
            }
        } 
        if(f[n][0]) puts("YES");
        else puts("NO");
        return 0;
    }

    B.[cf575b]Invariance of Tree

    给定n个数pi,问是否能构造一棵树,对于每条边连接的i,j, pi和pj也有连边   n<=100000

    题解:首先把i->pi连边,变成很多个环,如果存在一个点,那么全部连它即可。不然必须满足有一个长度为2的环,全部环都要是偶数,这样子就能对称的连起来。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 100000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,p[MN+5],q[MN+5],top=0,sz,len=-1;
    bool mark[MN+5];
    int flag,only,odd;
    
    void work(int x)
    {
        int y=flag;
        for(;!mark[x];x=p[x],y=p[y])
            printf("%d %d
    ",x,y),mark[x]=1;
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) p[i]=read();
        for(int i=1;i<=n;i++) if(!mark[i])
        {
            sz=1;mark[i]=1;q[++top]=i;
            for(int j=p[i];!mark[j];j=p[j]) mark[j]=1,sz++;
            if(sz==2) flag=i;
            else if(sz==1) only=i;
            else if(sz&1) odd=true;
        }
        if(only) 
        {
            puts("YES");
            for(int i=1;i<=n;i++)if(i!=only) printf("%d %d
    ",i,only);
            return 0;
        }
        if(odd||!flag)return 0*puts("NO");
        puts("YES");
        printf("%d %d
    ",flag,p[flag]);
        memset(mark,0,sizeof(mark));
        mark[flag]=1,mark[p[flag]]=1;
        for(int i=1;i<=n;i++)if(!mark[i]) work(i);
        return 0;
    }

    C.[cf651d]Image Preview

    有n张,两种的照片围起来,一种照片看需要1s,另一种需要b+1s,你一开始在一号照片处,移动一次要a s,你只有Ts的时间,求你最多能看多少。

    题解:显然情况只有三种,只看左右和同时看左右。前两种容易处理,剩下一种我们就二分一下最远点就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MN 1000000
    #define INF 200000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,a,b,ans=0;ll f[MN+5],T;
    char st[MN+5];
    
    int get(ll x,int i)
    {
    //    cout<<"get"<<x<<" "<<i<<endl;
        int l=i+1-n,r=n,mid,ans=INF;
        while(l<=r)
        {
            mid=l+r>>1;
            if(f[mid]<=x) ans=mid,r=mid-1;
            else l=mid+1;
        }
        return ans;
    }
    
    int get2(ll x,int i)
    {
    //    cout<<"get2 "<<x<<" "<<i<<endl;
        int l=n+2,r=i+n-1,mid,ans=-INF;
        while(l<=r)
        {
            mid=l+r>>1;
            if(f[mid]<=x) ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    
    int main()
    {
        n=read();a=read();b=read();T=read();
        scanf("%s",st+1);
        for(int i=1;st[i];i++) f[i]=f[i+n]=st[i]=='w'?b+1:1;
        for(int i=n;i;i--) f[i]+=f[i+1]+a;
        for(int i=n+2;i<=n<<1;i++) f[i]+=f[i-1]+a;
        for(int i=n+1;i<=n<<1;i++) 
        {
            if(f[i]>T) break;
            ans=max(ans,i-n);
            int L=get(T-f[i]+f[n+1]-a*(i-n-1),i);
        //    cout<<i<<" "<<L<<endl;
            ans=max(ans,i-L+1);
        }
        for(int i=n;i>=2;i--)
        {
            if(f[i]>T)break;
            ans=max(ans,n+2-i);
            int R=get2(T-f[i]+f[n+1]-a*(n+1-i),i);
        //    cout<<i<<" "<<R<<endl;
            ans=max(ans,R-i+1);
        }
        printf("%d
    ",ans);
        return 0;
    }

    D.[cf669d]Little Artem and Dance
    一开始有n个数1-n,有两种变换,一种是全部移动,一种是把现在的12,34,56......位的数字相互交换,求最后的数字顺序   n,q<=1000000

    题解:大模拟,移动容易处理,交换的话根据目前的状况特殊处理一下。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MN 1000000
    #define INF 200000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int rev=0,move=0,n,m,change=0;
    int ans[1000005];
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int op=read();
            if(op==1) move=(move+read()+n)%n;
            else 
            {
                if(!rev) rev=(move&1)?1:2;
                else
                if(move&1)
                {
                     if(rev==2) change+=1;
                     rev=0;
                }
                else
                {
                    if(rev==1) change-=1;
                    rev=0;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            int pos=i+move+change*((i&1)?2:-2);while(pos<n) pos+=n;
            if(rev){if((pos&1)^(move&1)==(rev&1))pos--;else pos++;}
            pos=(pos+n-1)%n+1;
            ans[pos]=i;
        }
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        return 0;
    }

    E.[cf687b]Remainers Game
    给定k和n个数ai,你可以知道所有x%ai的值,求是否可以知道x%k的值。

    题解:根据中国剩余定理,你可以猜出x%k的值,当且仅当存在m1,m2,m3..mm使得m1m2m3...mm=k且m1,m2,m3互质。所以分解x=p1^k1*p2^k2....,只要对于每个pi^ki都有数是他的倍数就行了。这样的话直接求lcm就好了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MN 1000000
    #define INF 200000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,k,a[MN+5],mn=0;
    bool b[MN+5],has[MN+5];
    int last[MN+5],num[MN+5];
    
    inline ll gcd(ll x,ll y){return (!y)?x:gcd(y,x%y);}
    
    int main()
    {
        n=read();k=read();if(!k)return 0*puts("Yes");
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            if(a[i]%k==0)return 0*puts("Yes");
        }
        ll ans=1;
        for(int i=1;i<=n;i++)
              ans=1LL*ans/gcd(ans,a[i])*a[i]%k;      
        if(!ans)puts("Yes");
        else puts("No");
        return 0;
    }
  • 相关阅读:
    Excel电子表格操作
    word文档编辑
    中英文输入
    个人借款合同范本
    Day-8:汇总数据
    Day-7:使用函数处理数据
    Day-6:创建计算字段
    Day-5:通配符过滤
    Day-4:高级数据过滤
    Day-3:过滤数据
  • 原文地址:https://www.cnblogs.com/FallDream/p/xunlian46.html
Copyright © 2020-2023  润新知