• Codeforces Round #448 (Div. 2)


    B. XK Segments

    题意

    给n,x,k,再n个数, 找出有多少对 (i,j)并且a[i] <= a[j],使得在  a[i] <= y <= a[j] 中有k个数可以整除x

    n, x, k (1 ≤ n ≤ 105, 1 ≤ x ≤ 109, 0 ≤ k ≤ 109),ai (1 ≤ ai ≤ 109) 

    分析

    直接unordered_map存[1,a[i] ]中有多少个能整除k

    k!=0的情况很显然,直接以当前数为左端点,找右端点的个数即可

    k==0时,加上和一样的数,不一样但整除数一样的求和/2即可

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn = 1e5 + 10;
    const ll mod = 1e9 + 7;
    ll n,x,k;
    ll a[maxn];
    unordered_map<ll,ll>mp;
    unordered_map<ll,ll>vis;
    
    int main()
    {
        scanf("%I64d%I64d%I64d
    ", &n, &x, &k);
        for(int i = 1;i <= n; i++)
        {
            scanf("%I64d", &a[i]);
            mp[a[i]/x]++;
            vis[a[i]]++;
        }
        ll sum = 0;
        ll ans=0, num=0;
        for(int i = 1; i <= n;i++)
        {
    
                if((a[i]%x)==0)
                {
                    if(k!=0)
                    sum += mp[k+a[i]/x-1];
                }
                else
                {
                    sum += mp[k+a[i]/x];
                    if(k==0)
                    {
                        ans+=vis[a[i]];
                       // mp[k+a[i]/x]-=vis[a[i]];
                        num+=mp[a[i]/x]-vis[a[i]];
                    }
                }
        }
        if(k!=0)
        printf("%I64d
    ", sum);
        else
            printf("%I64d
    ", ans+num/2);
        return 0;
    }
    View Code

    C.Square Subsets

    题意

    给n个数,问有多少选出任意个数相乘是平方数,答案对1e9+7取模

    (1 ≤ n ≤ 105)  ,ai (1 ≤ ai ≤ 70) 

    分析

    状压mask dp

    首先一个数是平方数,肯定是若干个素数,并且每个质数是偶数个,所以不难想到,如果将70以内的素数(19个),看成19个二进制位,分别化为s[i],表示每一个数二进制位的情况,如果每一位都是0的话,这个数则为平方数。

    定义:dp[i][j]表示前1~i个数,mask位 j 的方案数,则dp[70][0]则为答案

    转移:考虑当前数i,如果能转移到j,则dp[i][j]=(((dp[i-1][j]+dp[i-1][s[i]^j])%mod)*(fac[cnt[i]-1]))%mod;

    组合数C(n,m)从n和数选择m个数,选择奇数个和偶数个的总方案数都为2^(n-1),总的为2^n,因为每一个数都有两种状态0/1

    trick:注意将dp[0][0]设为1,并答案减去1,因为只有所有的数都选0个才不符合情况,显然这种情况这有一种

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn = 524300 ;
    const int maxm = 1e5 + 3;
    const ll mod = 1e9+7;
    
    int dp[71][maxn];
    int fac[maxm];
    int cnt[71];
    int prime[21]={2 ,3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67};
    int n;
    int s[71];
    
    
    int main()
    {
        for(int i = 1; i <= 70; i++)
        {
            int ii=i;
            for(int j = 0; j < 19; j++)
            {
                while(ii%prime[j] == 0)
                {
                    ii/=prime[j];
                    s[i]^=(1<<j);
    
                }
            }
        }
        fac[0]=1;
        fac[1]=2;
        for(int i = 2; i <= 100000; i++)
        {
            fac[i]=(2*fac[i-1])%mod;
        }
        scanf("%d", &n);
        int x;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &x);
            cnt[x]++;
        }
        dp[0][0]=1;
        for(int i = 1; i <= 70; i++)
        {
            if(!cnt[i])
            {
                for(int j = 0; j < (1<<19); j++)
                {
                    dp[i][j]=dp[i-1][j];
                }
            }
            else
            {
                for(int j = 0; j < (1<<19); j++)
                {
                  dp[i][j]=(((dp[i-1][j]+dp[i-1][s[i]^j])%mod)*(fac[cnt[i]-1]))%mod;
                }
            }
        }
        printf("%d
    ", dp[70][0]-1);
        return 0;
    }
    View Code

    D. String Mark

    题意

    分析


    E. Eyes Closed

    题意

    分析

    要么优秀要么生锈
  • 相关阅读:
    C语言实现快排
    C语言实现双向循环链表
    mysql插入数据后返回自增ID的方法
    golang flag包简单例子
    练习题 (六)
    练习题 (五)
    练习题 (四)
    练习题 (三)
    练习题 (二)
    练习题 (一)
  • 原文地址:https://www.cnblogs.com/Superwalker/p/7903792.html
Copyright © 2020-2023  润新知