Codeforces Round #630 (Div. 2)

Posted lanly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #630 (Div. 2)相关的知识,希望对你有一定的参考价值。

A. Exercising Walk (CF 1332 A)

题目大意

给定初始坐标((x,y))。有(a)次向左走((x-1)),有(b)次向右走((x+1)),有(c)次向下走((y-1)),有(d)次向上走((y+1))。给定(x_{1},y_{1},x_{2},y_{2}),问是否存在一种走的序列,使得坐标((x,y))始终满足(x_{1} leq x leq x_{2},y_{1} leq y leq y_{2})

解题思路

判断(x_{1} leq x-a+b leq x_{2},y_{1} leq y-c+d leq y_{2})即可。

特别地当(x_{1}=x_{2})的时候还要判断(a,b)是否同为(0)(y)同理。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

int main(void) {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        LL a,b,c,d,x,y,x1,y1,x2,y2;
        cin>>a>>b>>c>>d>>x>>y>>x1>>y1>>x2>>y2;
        LL xx=x+(b-a);
        LL yy=y+(d-c);
        bool qwq=0;
        if (xx>=x1&&xx<=x2&&yy>=y1&&yy<=y2) qwq=true;
        if (x1==x2&&(b!=0||a!=0)) qwq=false;
        if (y1==y2&&(c!=0||d!=0)) qwq=false;
        if (qwq) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}


B. Composite Coloring (CF 1332 B)

题目大意

(t)组询问,每组询问给定(n)合数(a_{i}),要求对(n)个数进行涂色,颜色数不超过(11),要求相同颜色的任意两个数的最大公因数大于(1)。输出一种可行涂色方案,不要求最小化颜色数。保证有解。

解题思路

由于(a_{i} leq 1000)且为合数,得知(a_{i})的因数中至少有一个小于(31)的质数,因为如果都大于(31)的话,会有(a_{i} geq 32^{2}=1024 > 1000)(a_{i} leq 1000)矛盾。而(31)刚好是第(11)个质数,所以我们就看一个数最小质数是多少给它涂上相应的颜色就就好了。

(此处直接暴力)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int t;
    read(t);
    while(t--){
        int n;
        read(n);
        int qwq[1005]={0};
        int ans[1005]={0};
        int cnt=0;
        for(int u,i=1;i<=n;++i){
            read(u);
            int up=sqrt(u);
            bool qaq=false;
            int tmp=u;
            for(int j=2;j<u;++j){
                if (u%j==0){
                    if (qwq[j]) {
                        ans[i]=qwq[j];
                        qaq=true;
                        break;
                    }
                    else if (tmp==u) tmp=j;
                }   
            }
            if (!qaq) ans[i]=qwq[tmp]=++cnt;
        }
        write(cnt,‘
‘);
        for(int i=1;i<=n;++i){
            printf("%d%c",ans[i],i==n?‘
‘:‘ ‘);
        }
    }
    return 0;
}


C. K-Complete Word (CF 1332 C)

题目大意

给定一个只包含小写字母的字符串(s)及一个数字(k(k|n)),每次操作可以拿任意一个小写字母替换一个位置的上的小写字母。要求最小化操作次数,使得字符串变成

  • (s)是个回文串
  • (s_{i}=s_{i+k} forall i in [1,n-k])

解题思路

目标串是一个由前缀串长度为(k)的重复(dfrac{n}{k})次得到的。由于(s_{1}=s_{n}=s_{k}),类似的等式可以证明这个长度为(k)的前缀串也是个回文串。那么对于每个重复串,每个从(1)(dfrac{k}{2})位,它们对应的字母一共有(2 imes dfrac{n}{k})个,我们取出现次数最多的字母作为这个位的字母,这样保留的字母就尽可能的多,替换的操作就尽可能的少了。

(k)为奇数的时候中间那个位的字母就只有(dfrac{n}{k})个。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int t;
    read(t);
    while(t--){
        int n,k;
        read(n);
        read(k);
        char s[n+1]={0};
        scanf("%s",s);
        int ans=0;
        int cu=(k>>1);
        for(int i=0;i<cu;++i){
            int cnt[28]={0};
            int qwq=0;
            for(int j=0;j<n/k;++j){
                cnt[s[j*k+i]-‘a‘]++;
                cnt[s[(j+1)*k-i-1]-‘a‘]++;
            }
            for(int j=0;j<26;++j) qwq=max(qwq,cnt[j]);
            ans+=qwq;
        }
        if (k&1){
            int cnt[28]={0};
            for(int j=0;j<n/k;++j){
                cnt[s[j*k+cu]-‘a‘]++;
            }
            int qwq=0;
            for(int j=0;j<26;++j) qwq=max(qwq,cnt[j]);
            ans+=qwq;
        }
        ans=n-ans;
        write(ans,‘
‘);
    }
    return 0;
}


D. Walk on Matrix (CF 1332 D)

题目大意

给定一个(n*m)的网格,每个网格上有一个数字,每次可以向右((y+1))或向下((x+1))移动一格,要求一种移动方式,使得从((1,1))移动到((n,m)),且到达的格子的所有数的&运算的值最大。

然而(Bob)写了个假(DP),如图。
技术图片

现在要求你构造一个矩阵,给定数字(k(k leq 10^{5})),满足以下要求:

  • (1 le n,m le 500)
  • (0 le a_{i,j} le 3 cdot 10^5, for all 1 le ile n,1 le jle m)
  • 真正的答案与(Bob)的假答案的差值恰好为(k)

解题思路

构造题。从简入手。

首先(1*m)的矩阵肯定不行,它们的差值为(0)

(2*2)的矩阵也不行,它们的差值为(0)

(2*3)的矩阵

[left( egin{array}{ccc} a & b & c d & e & f end{array} ight)]

对于真正的答案,是(max(abcf,abef,adef)) (abcf表示a&b&c&f)。

对于(Bob)的答案,是(max(abcf,max(abe,ade)f))

我们发现两者都有考虑到(abcf),那么我们让abcf尽可能小,否则两个都会取(abcf)而使得差值为0。很显然我们让(c)(0)就可以了。

然后,(Bob)与真正的答案是少考虑了一种情况,我们假设(adef)这个情况恰好就是最大值的情况,(Bob)只考虑了(abef),那就意味着abe>ade,但最终(adef>abef),且(adef-abef=k),这样就能符合题目的要求了。

那我们要怎么诱导(Bob)选择(abe)呢。注意到(k)(a_{i})的上限有(3)倍的差别。由于(10^{5})在二进制下有16位,而(3×10^{5})(18)位,我们让(a)前17位都是(1)(a=262143)),(b)的第17位是(1),其他位是(0)(b=131072)),而(d)的前(16)位全是(1)(d=131071)),(e=a),这样(abe=131072>ade=131071),然后我们再让(f=k),因为(k)在二进制下的第(17)位不可能是(1),这样(abef=0)(adef=k),就可以卡掉这个假DP了

[left( egin{array}{ccc} 262143 & 131072 & 0 131071 & 262143 & k end{array} ight)]

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int k;
    read(k);
    printf("2 3
");
    printf("262143 131072 0
");
    printf("131071 262143 %d
",k);
    return 0;
}


E. Height All the Same (CF 1332 E)

题目大意

给定一个(n*m)的网格,每个格子上有若干个方块,可以进行以下两种操作:

  • 对于相邻的格子(共边),可以分别放上一个方块。
  • 对于一个格子,可以放上两个方块。

给定数字(L,R),求出满足以下要求的初始局面的数量:

  • 每个格子初始的方块数(a_{ij})满足(L leq a_{ij} leq R)
  • 通过若干次操作后可以使得所有格子的方块数相同(等高)。

解题思路

对于第二个操作,它不会改变一个格子上方块数的奇偶性。如果所有格子的奇偶性相同,那么通过若干个操作二就一定能达到等高。否则我们需要通过操作一来改变奇偶性。

如果我们要全变成偶数,而有一对相邻的格子的方块数是奇数,那么我们对这对格子进行操作一就能变成偶数。

如果一奇一偶,我们进行操作一,那么奇数数量方块的格子就会移动,如果还有一个奇数数量方块的格子,我们就可以把这个格子移动到同样是奇数数量方块的格子使它们相邻,然后再一次操作一变成偶数。

那就很显然了,如果初始局面里,只要奇数数量方块的格子数量是偶数,或者偶数数量方块的格子数量的偶数,这个局面就能得到等高的局面,而无关乎它们的位置。

那就是个简单的计数问题。在([L,R])中,我们可以填(a)个奇数,(b)个偶数。

(n*m)是偶数,(ans=sumlimits_{0 leq i leq n ext{且} i\\%2==0}C^{i}_{n*m}*a^{i}*b^{n*m-i}=dfrac{(a+b)^{n*m}+(a-b)^{n*m}}{2})

(n*m)是奇数,(ans=sumlimits_{0 leq i leq n ext{且} i\\%2==0}(C^{i}_{n*m}*a^{i}*b^{n*m-i}+C^{i}_{n*m}*b^{i}*a^{n*m-i})=(a+b)^{n*m})

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const LL mo=998244353;

LL qpower(LL a,LL b){
    LL qwq=1;
    while(b){
        if (b&1) qwq=qwq*a%mo;
        a=a*a%mo;
        b>>=1;
    }
    return qwq;
}

LL inv(LL a){
    return qpower(a,mo-2);
}

int main(void) {
    LL n,m,l,r;
    read(n);
    read(m);
    read(l);
    read(r);
    LL a=(r+1)/2-l/2;
    LL b=r/2-(l-1)/2;
    LL ans=0;
    if (((n&1)==0)||((m&1)==0)) ans=(qpower(a+b,n*m)+qpower(a-b,n*m))%mo*inv(2)%mo;
    else ans=qpower(a+b,n*m);
    write(ans,‘
‘);
    return 0;
}


这次才注意到resubmission会-50白白扣了3次qwq

以上是关于Codeforces Round #630 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

codeforces630C

codeforces 630H (组合数学)

codeforces 630 I(规律&&组合)

codeforces 630K - Indivisibility