• Codeforces Round 609 Div2


    A

    题意

    找出两个合数使得他们差为某给出的数n

    思路

    先指定一个小的合数a,则b=a+n。若b是合数,则直接输出。若b是素数,则b+1一定不是素数。那么选一个a使得a,a+1均为合数即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    bool check(int x)
    {
        for(int i=2;i*i<=x;i++)
            if(x%i==0)return 0;
        return 1;
    }
    int main()
    {
        int n,a=8,b;
        scanf("%d",&n);
        b=a+n;
        while(check(a)||check(b))
            a+=1,b+=1;
        printf("%d %d
    ",b,a);
    }
    

    B

    题意

    给出两个数列a,b,一个整数m,求一个最小的x,使得a中所有元素加x再模m之后与b相等。

    思路

    要使得a最后与b相等,则a[0]必然会变成b中的一个元素,所以x的所有可能性一共2000种。所以 O(n^2) 的暴力测试所有可能性就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX=2005;
    
    vector<int>p;
    int a[MAX],b[MAX],c[MAX],n,m;
    
    bool check(int x)
    {
        for(int i=0; i<n; i++)
            c[i]=(a[i]+x)%m;
        sort(c,c+n);
        for(int i=0; i<n; i++)
            if(c[i]!=b[i])return 0;
        return 1;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        for(int i=0; i<n; i++)
            scanf("%d",&b[i]);
        sort(a,a+n);
        sort(b,b+n);
        for(int i=0; i<n; i++)
        {
            int aa=a[i],bb=b[0];
            if(aa<bb)p.push_back(bb-aa);
            if(aa>bb)p.push_back(bb+m-aa);
        }
        p.push_back(0);
        sort(p.begin(),p.end());
        unique(p.begin(),p.end());
        for(int i=0; i<p.size(); i++)
            if(check(p[i]))
            {
                printf("%d
    ",p[i]);
                break;
            }
    }
    

    C

    题意

    以数位的形式给出一个n位数a,再给出一个整数k,求一个最小的m位数b,使得b>a,并且对于任意i | 1<=i<=m-k,有b[i]==b[i+k]

    思路

    题意翻译一下就是b是由一个k位的数循环构成,尾部可以不足k位,所以只需要b的前k位大于等于a的前k位。要求b尽可能小,所以先用等于a的前k位构造b,再暴力比较一下,如果合法就输出,否则用a的前k位再加1构造,加一后可能存在进位,需要处理一下,但是不可能超过n位,因为999...这种情况一定能保证大于等于a

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX=2e5+5;
    
    char a[MAX],b[MAX];
    
    int main()
    {
        int n,k;
        scanf("%d%d%s",&n,&k,a+1);
        printf("%d
    ",n);
        for(int i=1; i<=k; i++)
            b[i]=a[i];
        for(int i=k+1; i<=n; i++)
            b[i]=b[i-k];
        bool flag=1;
        for(int i=1; i<=n; i++)
        {
            if(b[i]>a[i])
                break;
            if(b[i]<a[i])
            {
                flag=0;
                break;
            }
        }
        if(flag)
        {
            printf("%s
    ",b+1);
            return 0;
        }
        for(int i=k;i>0;i--)
        {
            if(b[i]=='9')
                b[i]='0';
            else
            {
                b[i]++;
                break;
            }
        }
        for(int i=k+1; i<=n; i++)
            b[i]=b[i-k];
        printf("%s
    ",b+1);
    }
    

    D

    题意

    给出一个由1x1的正方形组成的图形,左右下平整。求这个图形中最多能填充多少个1x2的骨牌。

    思路

    思维神题。貌似很dp,实际上只需要把这个图形涂成象棋棋盘一样的黑白格。设白色少于黑色(多于黑色交换一下就行)。则有:

    1. 任意黑色只与白色相邻,反之亦然。
    2. 黑色多于白色
    3. 一个骨牌需要一黑一白

    则由3可知,res=min(b,w) ,再由 1,2 可知所有白色格子一定可以匹配到一个黑色格子。所以可以推出答案就是白色的格子个数。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int n,x;
        long long b=0,w=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            b+=(x/2);
            w+=(x/2);
            if(i&1)b+=(x&1);
            else w+=(x&1);
        }
        printf("%I64d
    ",min(b,w));
    }
    

    E

    题意

    给出一个长度为n的排列p,每次操作可以交换相邻两数的位置。求对于k属于1-n的所有k,使得p中出现1-k的排列的最小操作次数(每个k独立)。

    思路

    对于连续的排列,则很明显就是求逆序数,但是本题难点在于k<n时,排列可能是被隔开的。所以需要先凑到一起。凑的话一定是两边向中间凑操作数最小。假设现在有k个数需要凑到一起。设数i当前的位置为s[i],凑到一起后的位置为t[i],凑到一起需要的操作次数为sum。则有:

    [egin{equation} egin{aligned} sum&=sum_{1}^k|s{[i]-t[i]|}\ \ sum&=sum_{s[i]>t[i]} s[i]-t[i]+sum_{t[i]>s[i]}t[i]-s[i]\\ &=sum_{right}s[i]-sum_{right}t[i]+sum_{left}t[i]-sum_{left}s[i]quad(1) end{aligned} end{equation} ]

    对于1式中中间两项,可以通过求出最中间的那个数的位置midpos来求出,左侧的t[i]一定是midpos-1,midpos-2......,右侧则为midpos+1,midpos+2......,则可以通过等差数列求和公式快速求出。而对于s[i],则可以通过树状数组维护,更新就在s[i]位置加s[i],这样求区间和就可以O(logn)的得到1式中的左右两项。

    而对于midpos,可以用set来维护,根据新插入数据在之前midpos的左右来更新midpos,保证midpos始终合法。

    所以总共用两个树状数组,一个维护逆序数,一个维护区间和,再用一个set维护midpos,总时间复杂度O(nlogn)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAX=2e5+5;
    
    int a[MAX],p[MAX],n;
    ll c1[MAX],c2[MAX];
    set<int>st;
    
    void add(ll *c,int x,int k)
    {
        for(;x<=n;x+=x&-x)
            c[x]+=k;
    }
    ll query(ll *c,int x)
    {
        ll sum=0;
        for(;x;x-=x&-x)
            sum+=c[x];
        return sum;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),p[a[i]]=i;
        st.insert(p[1]);
        auto it=st.begin();
        printf("0 ");
        add(c1,p[1],1);
        add(c2,p[1],p[1]);
        ll res=0;
        for(int i=2;i<=n;i++)
        {
            st.insert(p[i]);
            if(p[i]<(*it)&&i%2==0)it--;
            if(p[i]>(*it)&&i%2==1)it++;//保证偶数时右侧始终多于左侧1个,以保证后面的正确性。
            add(c1,p[i],1);
            res+=(i*1ll-query(c1,p[i]));
            add(c2,p[i],p[i]);
            int midpos=*it;
            ll sum=0,k=i/2;
            sum+=i&1?k*(midpos-1+midpos-k)/2:(k-1)*(midpos+midpos-k)/2;
            sum-=k*(midpos+1+midpos+k)/2;
            sum-=query(c2,midpos-1);
            sum+=query(c2,n)-query(c2,midpos);
            printf("%I64d ",res+sum);
        }
    }
    
  • 相关阅读:
    微服务架构最佳实践 基础设施篇
    深入理解微服务架构:银弹 or 焦油坑?
    uniapp canvasToTempFilePath
    uniapp easycom
    前端302通常不处理,通常使用链接
    linux性能监控命令dstat详解【杭州多测师_王sir】【杭州多测师】
    杭州市民卡面试题【杭州多测师】【杭州多测师_王sir】
    Java创建多线程的3种方式和Java当中的线程池【杭州多测师】【杭州多测师_王sir】
    Python笔试题:给定一个整数数组和一个目标值、找出数组中为2个俩个数、若无返回1【杭州多测师】【杭州多测师_王sir】
    GR/IR差异价格
  • 原文地址:https://www.cnblogs.com/cryingrain/p/12431556.html
Copyright © 2020-2023  润新知