zoukankan      html  css  js  c++  java
  • 5月16日vj题解

    CodeForces - 1033D 

    这题是让我们找到a=ai,即a为ai的积和,让我们找出a的因子个数;

    最终只需求出每个质因子的指数即可,我们可以使用一个map,记录每个质因子对应的指数。

    • 我们对数字进行分类,合法的有p2p2,p4p4,p3p3,pqpq
    • 前三种很好处理,现在考虑pqpq这种类型,如果a[i]=pqa[i]=pq那我们将所有数字都与a[i]a[i]求一次gcd,如果gcd(a[i],a[j])=pgcd(a[i],a[j])=p,那么可以直接更新map了。否则的话,质因子p,qp,q只在值为a[i]a[i]的数字中出现,我们统计一下这样的a[i]a[i]个数就好了。

    接下来是代码:

    #include<bits/stdc++.h>
    #define maxn 110000
    #define rep(i,a,b)  for(int i=a;i<b;i++)
    using namespace std;
    #define ll long long 
    int gi() {
        int x = 0; char c = getchar();
        while (c < '0' || c > '9') c = getchar();
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    #define mod 998244353
    //123****123
    map<ll, int>test;
    ll a[maxn];
    ll gcd(ll a, ll b)
    {
        return !b ? a : gcd(b, a % b);//本代码的核心,gcd约分代码
    
    }
    int main()
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
        }
        for (int i = 1; i <= n; i++)
        {
            ll p = sqrt(a[i]);
            if (p * p == a[i])
            {
                ll tmp = sqrt(p);
                if (pow(tmp, 4) == a[i])
                {
                    test[tmp] += 4;
                }
                else
                {
                    test[p] += 2;
                }
                continue;
            }
             p = cbrtl(a[i]);
            if (pow(p, 3) == a[i]) {
                test[p] += 3;
                continue;
            }
            bool lazy = false;
            for (int j = 1; j <= n&&!lazy; j++)
            {
                if (a[i] != a[j])
                {
                    ll g = gcd(a[i], a[j]);
                    if (g != 1)
                    {
                        test[g]++;
                        test[a[i] / g]++;
                        lazy = true;
                        break;
                    }
                }
            }
            if (!lazy)
            {
                test[a[i]] = sqrt(test[a[i]] + 1) + 1;
                test[a[i]] = test[a[i]] * test[a[i]] - 1;
            }
        }
        ll sum = 1;
        for (auto i : test)
        {
            sum = sum * (i.second + 1) % mod;
        }
        cout << sum << endl;
    }

    CodeForces - 1066E

    题目大意:

    给你两个数

      1、给出两个大数a和b,要求计算(a&b) + (a & (b >> 1)) + (a & (b >> 2)) + ...

      2、答案累加上一个操作的值

    然后最终答案并且取摸998244353

    题解:
    因为第一个二进制不动,第二个在动,所以预处理第一个数获得答案,因为是and(与),所以只有2个都为1是才有贡献,例如样例:

    1001

    11010,

    就会产生以下几种情况:
    01001

    11010

    1001 

    1101

    1001

    0011

    1001

    0110

    1001

    0001

    我们会发现,第一位的1分别和上面的第一个1和最后一个1异或起来对答案有贡献

    所以这个1对答案的贡献是8+1=9

    我们把这个规律推广开来

    对y中每一个1进行如上操作

    即可得出答案

    但是,我们会发现答案复杂度是O(n×m)的,过不了

    所以我们要预处理

    用前缀和跑一遍x即可

    复杂度优化到O;

    #include<assert.h>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    //#include<bits/stdc++.h>
    #define maxn 210000
    #define rep(i,a,b)  for(int i=a;i<b;i++)
    using namespace std;
    #define ll long long 
    int gi() {
        int x = 0; char c = getchar();
        while (c < '0' || c > '9') c = getchar();
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    #define mod 998244353
    //123****123
    map<ll, int>test;
    ll gcd(ll a, ll b)
    {
        return !b ? a : gcd(b, a % b);//本代码的核心,gcd约分代码
    
    }
    char a[maxn], b[maxn];
    int sum[maxn];
    int main()
    {
        int n, m;
        while (cin >> n >> m)
        {
            for (int i = n; i >= 1; i--)
            {
                cin >> a[i];
            }
            for (int i = m; i >= 1; i--)
            {
                cin >> b[i];
                sum[i] = sum[i + 1] + b[i] - '0';
            }
            ll ans = 0, pw = 1;
            for (int i = 1; i <= n; i++)
            {
                if (a[i] == '1')
                {
                    ans = (ans + (sum[i] * pw) % mod) % mod;
                }
                pw = pw * 2 % mod;
            }
            cout << ans << endl;
        }
    }

    Codeforces 1043F(容斥+dp)

    Problem:给n个数(n<=3e5),每个数<=3e5,选择最少的数,使得他们的gcd为1。输出这个最小子集的大小。
    Idea:Idea:Idea:可以二分,或者直接枚举,因为2 * 3 * 5 * 7 * 11 * 13 * 17 > 3e5,每次选择会删去一个素数,所以答案不超过7。接着用莫比乌斯反演验证答案是否存在,g(x,len)表示集合大小为len,gcd为x的倍数的方案数,那么验证f(1, len)的方案数不为0即可。

    代码一

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int N = 3e5+10;
    const int MOD = 1e9+7;
    
    bool isn[N];
    int mu[N], p[N];
    LL inv[N], fac[N];
    
    void init() {
        inv[1] = 1;
        for(int i = 2; i < N; ++i) inv[i] = MOD-(MOD/i*inv[MOD%i]%MOD);
        fac[0] = 1, inv[0] = 1;
        for(int i = 1; i < N; i++){
            fac[i] = fac[i-1]*i%MOD;
            inv[i] = inv[i-1]*inv[i]%MOD;
        }
        int pnt = 0;
        isn[1] = 1; mu[1] = 1;
        for(int i = 2; i < N; i++) {
            if(!isn[i]) { p[pnt++] = i; mu[i] = -1; }
            for(int j = 0; j<pnt && i*p[j]<N; j++) {
                isn[i*p[j]] = 1;
                if(i%p[j] == 0) { mu[i*p[j]] = 0; break; }
                mu[i*p[j]] = -mu[i];
            }
        }
    }
    
    inline LL C(int a, int b) { return fac[a]*inv[b]%MOD*inv[a-b]%MOD; }
    
    int cnt[N];
    
    int main() {
        init();
        int n, g; scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            int x; scanf("%d", &x);
            if(i == 1) g = x;
            else g = __gcd(g, x);
            cnt[x]++;
        }
        if(g != 1) { puts("-1"); exit(0); }
        for(int i = 1; i < N; i++)
        for(int j = i+i; j < N; j += i)
            cnt[i] += cnt[j];
        for(int i = 1; i <= min(n, 7); i++) {
            LL sum = 0;
            for(int j = 1; j < N; j++) if(cnt[j] >= i) {
                (sum += mu[j]*C(cnt[j], i)) %= MOD;
            }
            if(sum) { printf("%d
    ", i); break; }
        }
        return 0;
    }

    代码二

    #include<bits/stdc++.h>
    using namespace std;
    long long n,m,i,j,ii,now,A,B,f[300001],a[300001],cnt1[300001],cnt2[300001];
    long long gcd(long long n1,long long m1){
        if(!m1)return n1;
        return gcd(m1,n1%m1);
    }
    int main(){
        scanf("%lld",&n);
        for(i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            if(a[i]==1){
                puts("1");
                return 0;
            }
            cnt1[a[i]]=cnt2[a[i]]=1;
        }
        now=a[1];
        for(i=2;i<=n;i++)now=gcd(now,a[i]);
        if(now>1){
         puts("-1");
         return 0;
    }
        for(i=2;i<=n;i++){
            for(j=3e5;j;j--){
                A=B=0;
             for(ii=j;ii<=3e5;ii+=j){
                 f[j]-=f[ii];
                 A+=cnt1[ii];B+=cnt2[ii];
             }
             f[j]+=A*B;
         }
            for(j=1;j<=3e5;j++){
             f[j]=min(1ll,f[j]);
             cnt2[j]=f[j];
        }
           if(cnt2[1]>0){
               printf("%lld",i);
               return 0;
           }
        }
    }
  • 相关阅读:
    Cmder配置
    uboot移植
    嵌入式产品开发技术问题
    flexbox布局
    使用PS过程
    STM32 使用 FreeRTOS过程记录
    TTL、RS232、RS485、串口
    用纯css改变下拉列表select框的默认样式
    task9暂存
    Hello World
  • 原文地址:https://www.cnblogs.com/csxaxx/p/12900461.html
Copyright © 2011-2022 走看看