Codeforces Round #705 (Div. 2)

2022-08-08 17:38:05 浏览数 (1)

A. Anti-knapsack

题意

给你k和n,让你在1-n中找不重复的数组成一个集合,要求集合的任意子集的所有数字加起来不等于k,求最大的集合。

分析

首先,大于k的肯定可以放入集合(无论怎么加都是大于k的),k不能放入集合(否则k一个数组成的子集等于k),再考虑小于k的数,可以发现,拿所有大于等于k/2的数也都是可行的(任意两个数加起来都大于k,切每个数本身都小于k),代码就出来了。

代码

代码语言:javascript复制
#include <bits/stdc  .h>
#define LL long long
using namespace std;
const int maxn = 1e5 10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;

int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    while(t--) {
        int n, k;
        cin >> n >> k;
        vector<int> ans;
        for(int i = k 1; i <= n; i  ) ans.push_back(i);
        for(int i = k-1; i >= k-k/2; i --) ans.push_back(i);
        cout << ans.size() << endl;
        for(int i = 0; i < ans.size(); i  ) printf("%d%c",ans[i],i == ans.size() - 1 ? 'n' : ' ');
    }
    return 0;
}

B. Planet Lapituletti

题意

告诉你一个地区的时间进位方式h,m(如h = 26,m = 50表示一天26小时,每小时50分钟),再告诉你现在的时间hh:mm,要求你找到离现在最近的一个时间点,满足镜面反射的时间也是合法的(即不超过h和m),若当天没有则可以跨越到第二天。

分析

首先,根据镜面反射的特点可知:0、1、8不变,2会变5,5会变2,其余的都是非法的。由于数据量不大,可以直接暴力每一分钟,每次检查一下这个时间点的镜面是否也合法即可。由于有前导零,镜面反射的时候会有影响(01遍10),推荐用字符串表示时间,计算的时候再转换成数字。

代码

代码语言:javascript复制
#include <bits/stdc  .h>
#define LL long long
using namespace std;
const int maxn = 1e5 10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
int h, m;
bool judge(char *t) {
    char s[10];
    memcpy(s,t,5);
    for(int i = 0; i < 5; i  ) {
        if(i == 2) continue;
        if(s[i] == '2') s[i] = '5';
        else if(s[i] == '5') s[i] = '2';
        else if(s[i] == '3' || s[i] == '4' || s[i] == '6' || s[i] == '7' || s[i] == '9') return 0;
    }
    int x = (s[4] - '0') * 10   s[3] - '0';
    int y = (s[1] - '0') * 10   s[0] - '0';
    if(x < h && y < m) return 1;
    return 0;
}

int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    while(t--) {
        char clo[10];
        cin >> h >> m >> clo;
        while(judge(clo) == 0) {
            int y = (clo[3] - '0') * 10   clo[4] - '0';
            y  ;
            if(y == m) {
                int x = (clo[0] - '0') * 10   clo[1] - '0';
                x  ;
                y = 0;
                if(x == h) x = 0;
                clo[0] = x/10 '0';
                clo[1] = x % 10   '0';
            }
            clo[3] = y / 10   '0';
            clo[4] = y % 10   '0';
        }
        cout << clo << endl;
    }
    return 0;
}

D. GCD of an Array

题意

给你n个数存入数组a中,q次询问。每次询问给你i和x,表示将a[i]乘上x后,输出n个数的gcd。

分析

求n个数的gcd,我们假设这 n 个数的gcd为 p = 84 ,将 p 分解质因数后得到 p = 2 * 2 * 3 * 7 ,说明这n个数分解质因数后每个数也都包含 2 , 2 , 3 , 7 这几个质因数。也就是说,我们需要记录一下每个数的每个质因数j出现的次数k,然后记录一下每个质因数j出现k次的次数,如果出现k次的次数达到了n次,则表示每个数字都含有k个质因数j,那么gcd分解质因数后也会有k个质因数j,上述的两个记录可以通过两个map来实现。对于每次询问,会在 i 这个位置乘 x ,实际上就是给i这个位置贡献了若干个由x分解得来的质因数,维护一下map对应的值,再判断是否到达 n 次,如果到达 n 次则 gcd 乘上这个质因数(因为每次质因数j出现k次的次数只会有一次到达n次,所以不会重复计算)。

代码

代码语言:javascript复制
#include <bits/stdc  .h>
using namespace std;

const long long N = 501000;
const long long mod = 1e9 7;

long long a[N], n, m;
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
unordered_map<int,map<int,int>> mp,cnt;
long long ans = 1;
void solve(int pos, int x) {
    for (int j = 2; j <= sqrt(x); j  ) {
        while (x % j == 0) {
            //第pos个位置对应的数中质因数j出现的次数 1
            mp[pos][j]  ;
            //质因数j出现mp[pos][j]次的次数 1
            cnt[j][mp[pos][j]]  ;
            //设mp[pos][j]= k
            //如果质因数j出现k次的次数达到n次,则说明gcd中有k个质因数j相乘,
            //但由于既然每个数中同时有k个j,那肯定也满足同时有k-1个j,
            //故这次只要将答案乘以j就行了,k-1个已经在之前乘过了。
            if (cnt[j][mp[pos][j]] == n) ans = (ans * j) % mod;
            x /= j;
        }
    }
    //别忘了x不为1的话也是一个质因数,处理方式同上
    if (x > 1) {
        mp[pos][x]  ;
        cnt[x][mp[pos][x]]  ;
        if (cnt[x][mp[pos][x]] == n) ans = (ans * x) % mod;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i  ) {
        scanf("%lld", &a[i]);
        solve(i,a[i]);
    }
    while (m--) {
        long long pos, mul;
        scanf("%d %lld",&pos, &mul);
        solve(pos,mul);
        printf("%lldn",ans%mod);
    }
    return 0;
}

0 人点赞