• 2017-4-6校内训练


    cf训练赛

    A.题目大意:给出n个数,问能否选出若干个数,使得这些数的和为m的倍数。(n<=10^6,m<=10^3)

    思路:用f[i][j]表示前i个数是否能选出若干个和模m为j的数,直接DP,当f[i][0]为true时直接返回,虽然看上去是O(nm),但我们可以发现,当n超过m时答案必为真,证明如下:每次加入一个数x,若x不能被前i-1个数表示,我们令f[i][x]=true;若x能被前i-1个数表示,则2x能被前i个数表示,以此类推,每次加入x,至少会有一个原来为false的被设为了true,否则说明我们找到了m的倍数。总复杂度O(m^2)。

    #include<cstdio>
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 1000
    int u[2][MN+5];
    int main()
    {
        int n,m,x,i;
        n=read();m=read();
        while(n--)
        {
            u[n&1][x=read()%m]=1;
            for(i=0;i<m;++i)if(u[n&1^1][i])u[n&1][i]=u[n&1][(i+x)%m]=1;
            if(u[n&1][0])return 0*puts("YES");
        }
        puts("NO");
    }

    B.题目大意:给出一个1~n的置换,要求构造一棵n个点的树,使得树上每条边两端点编号置换后得到的边仍然出现在树中。(n<=10^5)

    思路:先把置换拆成若干个循环,如果有长度为1的循环,那么其他所有点连到这个点即可,否则只有所有循环长度均为偶数且存在长度为2的循环才可以构造,选出一个长度为2的循环,其他所有点根据在循环中位置的奇偶分别连向这个循环的两个点,最后把这两个点自己连起来即可。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    int a[MN+5],u[MN+5],cnt;
    vector<int> v[MN+5];
    int main()
    {
        int n=read(),i,j,s,s1=0,s2=0,o=0;
        for(i=1;i<=n;++i)a[i]=read();
        for(i=1;i<=n;++i)if(!u[i])
        {
            for(++cnt,j=i;!u[j];u[j]=1,j=a[j])v[cnt].push_back(j);
            s=v[cnt].size();
            if(s==1)s1=cnt;
            if(s==2)s2=cnt;
            o|=s&1;
        }
        if(!s1&&(o||!s2))return 0*puts("NO");
        puts("YES");
        for(i=1;i<=cnt;++i)
            if(s1)for(j=0;j<v[i].size();++j){if(i!=s1)printf("%d %d
    ",v[i][j],v[s1][0]);}
            else if(i!=s2)for(j=0;j<v[i].size();++j)printf("%d %d
    ",v[i][j],v[s2][j&1]);
        if(!s1)printf("%d %d
    ",v[s2][0],v[s2][1]);
    }

    C.题目大意:你有n张图片,你一开始翻到第1张,每次从第i张切换到第i-1或第i+1张需要a的时间(1可以切换到n,n可以切换到1),每张图片的朝向可能不太对,如果碰见朝向不对的,你需要花b时间转过来,每次你碰见第一次看到的图片,你会花1时间看它,问在t时间内最多看多少张图片。(n<=500,000)

    思路:只会有两种情况,一种先往左边翻,然后再翻到右边,另一种先翻到右边再翻到左边,若只考虑先翻右的(另一种同理),可以预处理出从第1张翻到左边每一张时的花费,从左往右枚举右端点,显然左端点也递增,拿两个指针直接统计即可,总复杂度O(n)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MN 500000
    char g[MN+5];
    int n,a,b,t,ans,f[MN+5];
    void solve()
    {
        int i,j,s;
        for(i=n;i--;)f[i]=f[i+1]+a+b*(g[i]=='w')+1;
        for(i=j=s=0;i<n;++i,s+=a)
        {
            s+=b*(g[i]=='w')+1;
            if(s>t)break;
            ans=max(ans,i+1);
            if(s+i*a<=t)
            {
                while(j<=i||s+f[j]+i*a>t)++j;
                ans=max(ans,i+1+n-j);
            }
        }
    }
    int main()
    {
        scanf("%d%d%d%d%s",&n,&a,&b,&t,g);
        solve();
        for(int i=1;i<n-i;++i)swap(g[i],g[n-i]);
        solve();
        printf("%d",ans);
    }

    D.题目大意:一个1~n的排列一开始为1,2,3,…,n,支持两种操作:1.循环右移k位;2.交换当前第1个和第2个,第3个和第4个……保证n为偶数。(n<=1,000,000,操作数<=2,000,000)

    思路:把排列编号为0~n-1,两种操作分别表示为x=(x+k)mod n,x=x xor 1,显然如果奇偶性相同,偏移量也相同,两种情况都算一下即可,复杂度O(n)。

    #include<cstdio>
    inline int read()
    {
        int x,f=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return f?x:-x;
    }
    #define MN 1000000
    int ans[MN+5];
    int main()
    {
        int n=read(),i,t,x,s0=0,s1=1;
        for(i=read();i--;)
        {
            t=read();
            if(t==1)x=read(),s0=(s0+x)%n,s1=(s1+x)%n;
            else s0^=1,s1^=1;
        }
        for(i=1;i<=n;++i)ans[(i+(i&1?s0:s1-1)+n)%n]=i;
        for(i=1;i<=n;++i)printf("%d ",ans[i%n]);
    }

    E.题目大意:给出n个数ci和一个数k,问是否对于任意的x,若确定所有x%ci,则可确定x%k。(n,k,ci<=1,000,000)

    思路:显然要确定x%k的条件为k|lcm(ci),筛法预处理后把ci和k分解质因数,对每个质因子统计一下即可。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 1000000
    int f[MN+5],p[MN+5],pn,s[MN+5];
    int main()
    {
        int n,k,i,j,cnt;
        for(i=2;i<=MN;++i)
        {
            if(!f[i])f[i]=i,p[++pn]=i;
            for(j=1;i*p[j]<=MN;++j){f[i*p[j]]=p[j];if(i%p[j]==0)break;}
        }
        n=read();k=read();
        while(n--)for(i=read();i>1;)
        {
            for(j=f[i],cnt=0;f[i]==j;i/=j)++cnt;
            s[j]=max(s[j],cnt);
        }
        while(k>1)
        {
            for(j=f[k],cnt=0;f[k]==j;k/=j)++cnt;
            if(s[j]<cnt)return 0*puts("No");
        }
        puts("Yes");
    }
  • 相关阅读:
    Html5——视频标签使用
    Android的四大组件
    Android 硬编码
    按键事件处理
    android Keycode 完全对照表
    Activity的生命周期
    音乐播放控制
    Android permission 访问权限大全
    制作留言板相关资料
    adb查询log命令
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170406C.html
Copyright © 2020-2023  润新知