Codeforces Round #615 (Div. 3)

六月ゝ 毕业季﹏ 提交于 2020-01-23 03:53:19

暂时没有F题的题解。太菜了。

A - Collecting Coins

题意:有三个人,分别有a,b,c枚硬币,你有n枚硬币,要求把n枚硬币全部给这三个人并且使得他们的硬币数变为相等。问是否可行。

题解:先验证硬币总数a+b+c+n是否能被3整除,然后验证要补的硬币的数量少于n。

void test_case() {
    int a[5], n;
    scanf("%d%d%d%d", &a[1], &a[2], &a[3], &n);
    sort(a + 1, a + 1 + 3);
    int sum = a[3] - a[1] + a[3] - a[2];
    if(sum > n || (sum - n) % 3 != 0)
        puts("NO");
    else
        puts("YES");
}

B - Collecting Packages

题意:有个机器人,只能向上走或者向右走,要从(0,0)经过所有的点(xi,yi),求是否可行,若可行则输出字典序最小的方案。

题解:字典序最小就是说先往右走再往上走。直接把所有点按x排序,要求每个点与(0,0)包围的矩形包含此前的所有点,只需要比前面的点都高就行了。由数学归纳法可知只需要比前一个点高就行了。

int n;
pii p[1005];
 
void test_case() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        p[i] = {x, y};
    }
    sort(p + 1, p + 1 + n);
    for(int i = 2; i <= n; ++i) {
        if(p[i].second < p[i - 1].second) {
            puts("NO");
            return;
        }
    }
    puts("YES");
    int cx = 0, cy = 0;
    for(int i = 1; i <= n; ++i) {
        while(cx < p[i].first) {
            putchar('R');
            ++cx;
        }
        while(cy < p[i].second) {
            putchar('U');
            ++cy;
        }
    }
    putchar('\n');
}

C - Product of Three Numbers

题意:给一个数n,满足n>=2,要求将n分解成互异的三个数a,b,c,使得a*b*c==n,且a,b,c>=2。给出一种分解的方案,或者说明其不存在。

题解:一开始没看见>=2直接判断质数就上了(虽然这样也不对,比如9不能分解为1,3,3),仔细一想跟质数的种类有关系,所以可以直接分解质因数。假如有3种以上的质因数,那么前两个数要两种,剩下的最后一个数补位就是一种字典序最小的构造。假如只有1种质因数,那么肯定至少需要6次,前两个数分别要1次和2次,剩下的至少要3次,这也是一种字典序最小的构造。假如有2种质因数,那么总次数<=3的显然是无解的,而总次数>=4的必定有解。首先把两种质因数各1次拿出来,那么剩下的那个2次也不会和前面的重复,只是这样并不是字典序最小(还好题目没要求)。

最简单的思路也是字典序最小的思路就是直接暴力枚举a和b。

下面这个质因数分解的模板貌似还带有筛出最小质因子的功能的。

const int MAXN = 1e5;
int p[MAXN + 5], ptop;
int pn[MAXN + 5];
 
void sieve() {
    int n = MAXN;
    pn[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!pn[i])
            p[++ptop] = i;
        for(int j = 1; j <= ptop; j++) {
            int t = i * p[j];
            if(t > n)
                break;
            pn[t] = p[j];
            if(i % p[j] == 0)
                break;
        }
    }
}
 
int fac[105][2], ftop;
 
void get_fac(int n) {
    ftop = 0;
    for(int i = 1; i <= ptop; ++i) {
        if(n % p[i] == 0) {
            fac[++ftop][0] = p[i];
            fac[ftop][1] = 0;
            while(n % p[i] == 0) {
                n /= p[i];
                ++fac[ftop][1];
            }
        }
    }
    if(n > 1) {
        fac[++ftop][0] = n;
        fac[ftop][1] = 1;
    }
}
 
void test_case() {
    int n;
    scanf("%d", &n);
    get_fac(n);
    if(ftop >= 3) {
        puts("YES");
        printf("%d %d %d\n", fac[1][0], fac[2][0], n / fac[1][0] / fac[2][0]);
        return;
    } else if(ftop == 1) {
        if(fac[1][1] >= 6) {
            puts("YES");
            printf("%d %d %d\n", fac[1][0], fac[1][0]*fac[1][0], n / fac[1][0] / fac[1][0] / fac[1][0]);
            return;
        } else {
            puts("NO");
            return;
        }
    } else {
        int sum = fac[1][1] + fac[2][1];
        if(sum <= 3) {
            puts("NO");
            return;
        } else {
            puts("YES");
            printf("%d %d %d\n", fac[1][0], fac[2][0], n / fac[1][0] / fac[2][0]);
            return;
        }
    }
}

D - MEX maximizing

题意:有q次操作和一个固定的正整数x,每次操作会往序列中加入一个数字y,你可以在任何时候对序列中的某个y进行任意多次加减x操作(但不能使他们变成负数),求使得整个序列的MEX最大的方案时的MEX的值。

题解:显然模x余数相同的都是同一种等价的东西,可以维护模x值不同结果的cnt。那么MEX操作就相当于询问整个cnt序列中的最小值(这个最小值是一层一层循环叠在下面把MEX垫高),然后再求序列中等于这个最小值的最左边的元素,这个显然可以用线段树来维护(甚至可以支持修改删除)。

但是最简单的操作还是在cnt里面数了之后不断尝试越过MEX即可。

E - Obtain a Permutation

题意:给一个n*m的矩阵,要求复原成形如:

1  2  3  4
5  6  7  8
9  10 11 12

的样子,也就是依次填充。

有两种cost都是1的操作,1种是直接修改某位置的数字,另一种是把一列向上轮换。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!