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\n",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\n",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",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\n",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\n",b+1);
}
D
题意
给出一个由1x1的正方形组成的图形,左右下平整。求这个图形中最多能填充多少个1x2的骨牌。
思路
思维神题。貌似很dp,实际上只需要把这个图形涂成象棋棋盘一样的黑白格。设白色少于黑色(多于黑色交换一下就行)。则有:
- 任意黑色只与白色相邻,反之亦然。
- 黑色多于白色
- 一个骨牌需要一黑一白
则由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\n",min(b,w));
}
E
题意
给出一个长度为n的排列p,每次操作可以交换相邻两数的位置。求对于k属于1-n的所有k,使得p中出现1-k的排列的最小操作次数(每个k独立)。
思路
对于连续的排列,则很明显就是求逆序数,但是本题难点在于k<n时,排列可能是被隔开的。所以需要先凑到一起。凑的话一定是两边向中间凑操作数最小。假设现在有k个数需要凑到一起。设数i当前的位置为s[i],凑到一起后的位置为t[i],凑到一起需要的操作次数为sum。则有:
对于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);
    }
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号