• Codeforces Round #391 A B C D E


    A. Gotta Catch Em' All!

    题意

    从给定的字符串中选取字符,问可构成多少个(Bulbasaur)

    // 想到柯南里一些从报纸上剪汉字拼成的恐吓信_(:з」∠)_

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    int cnt[256];
    char dict1[] = {'B', 'l', 'b', 's', 'r'};
    char dict2[] = {'u', 'a'};
    char s[maxn];
    int main() {
        scanf("%s", s);
        int len = strlen(s), ans=len;
        F(i, 0, len) ++cnt[s[i]];
        F(i, 0, 5) ans = min(ans, cnt[dict1[i]]);
        F(i, 0, 2) ans = min(ans, cnt[dict2[i]]>>1);
        printf("%d
    ", ans);
        return 0;
    }
    
    

    B. Bash's Big Day

    题意

    (n)个数中挑尽可能多的数使得它们的(gcdgt 1)

    思路

    法一

    将每个数质因子分解

    法二

    对于每个质数,枚举其倍数

    注意:特判一个数的情况

    Code

    Ver. 1: 93ms

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    int cnt[maxn];
    void divide(int x) {
        for (int i = 2; ; ++i) {
            if (i*i>x) break;
            if (x%i==0) {
                ++cnt[i];
                while (x%i==0) x /= i;
            }
        }
        if (x>1) ++cnt[x];
    }
    int main() {
        int n, x, ans=0;
        scanf("%d", &n);
        F(i, 0, n) {
            scanf("%d", &x);
            divide(x);
        }
        F2(i, 2, maxn-10) ans = max(ans, cnt[i]);
        printf("%d
    ", ans?ans:1);
        return 0;
    }
    
    

    Ver. 2: 31ms

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 100000
    using namespace std;
    typedef long long LL;
    int num[maxn+10], cnt[maxn+10], prime[maxn], tot;
    bool vis[maxn+10];
    void work(int x) {
        for (int i = 1; ; ++i) {
            if (i*x>maxn) break;
            cnt[x] += num[i*x];
        }
    }
    void init() {
        F2(i, 2, maxn) {
            if (!vis[i]) prime[tot++] = i;
            work(i);
            F(j, 0, tot) {
                if (i*prime[j]>maxn) break;
                vis[i*prime[j]]=true;
                if (i%prime[j]==0) break;
            }
        }
    }
    int main() {
        int n, x, ans=0;
        scanf("%d", &n);
        F(i, 0, n) {
            scanf("%d", &x);
            ++num[x];
        }
        init();
        F2(i, 0, maxn) ans = max(ans, cnt[i]);
        printf("%d
    ", ans?ans:1);
        return 0;
    }
    

    C. Felicity is Coming!

    题意

    (n)种动物,(m)个山洞,每个山洞中有(g_i)个动物(种类可重复)。

    (f)为一个双射,(f(x)=y)即将动物(x)变成动物(y).

    求有多少满足条件的(f),使得变化之后每个山洞中的动物分布与之前完全相同。

    思路

    即找对于动物来说,有多少个等价类,每个等价类中可以全排列

    怎么找有多少个等价类呢?

    动物(x)与动物(y)等价,当且仅当它们在每个山洞中的出现次数都相同。

    因此,对每个动物开一个(vector),表示它们在哪些山洞中出现,出现多次则记录多次。

    则,(xleftrightarrow yiff v[x]==v[y])

    (v)排序即可

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 1000010
    using namespace std;
    typedef long long LL;
    int n, m, x, y;
    LL f[maxn];
    vector<int> v[maxn];
    const LL mod=1e9+7;
    void init() {
        f[0] = 1;
        F2(i, 1, m) f[i] = f[i-1]*i%mod;
    }
    int main() {
        scanf("%d%d", &n,&m);
        F(i, 0, n) {
            scanf("%d", &x);
            F(j, 0, x) {
                scanf("%d", &y);
                v[y].push_back(i);
            }
        }
        init();
        sort(v+1, v+1+m);
        int cnt=1; LL ans=1;
        F2(i, 2, m) {
            if (v[i]==v[i-1]) ++cnt;
            else {
                (ans *= f[cnt]) %= mod;
                cnt=1;
            }
        }
        (ans *= f[cnt]) %= mod;
        printf("%I64d
    ", ans);
        return 0;
    }
    
    

    D. Felicity's Big Secret Revealed

    题意

    将一个长度为(n)(01)(s)进行分割,对于(s_1|s_2|cdots|s_{k-1}|s_{k}),其中有效的数字为(s_2,s_3,cdots,s_{k-1}),设其中的最大数为(m). 我们称一个分割为有效的,当且仅当(s_2,s_3,cdots,s_{k-1})连续地构成(1-m)的所有数(可重复)。

    问有多少个有效的分割。

    思路

    参考:http://www.cnblogs.com/widsom/p/7417983.html

    因为(nleq 75),而1(1 bits) + 2(2 bits) + 4(3 bits) + 8(4 bits) + 5*(5 bits) = 74 bits,故最大数不会超过(20),故进行状压(dp).

    状态(state):第(i)位为(1)当且仅当集合中有该数(i)

    (dp[i][j])表示最后一刀切在(i)之前,得到的集合状态为(state)的情况总数。

    至于有效的分割怎么处理呢?最后统计答案时直接统计(state)(2)的幂次(-1)的情况即可,处理中途不用管(也无法管)。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 80
    #define maxl 1100000
    using namespace std;
    typedef long long LL;
    const int mod = 1e9+7;
    int num[maxn][maxn], n, dp[maxn][maxl];
    char s[maxn];
    void init() {
        F(i, 0, n) {
            int x=0;
            F(j, i, n) {
                num[i][j] = ((x<<=1) += s[j]-'0');
            }
        }
    }
    int main() {
        scanf("%d%s", &n, s);
        init();
        int lim=(1<<20)-1;
        F2(i, 0, n) {
            dp[i][0] = 1;
            F(j, 0, lim) {
                if (!dp[i][j]) continue;
                F2(k, i+1, n) {
                    if (num[i][k-1]>20) break;
                    if (!num[i][k-1]) continue;
                    (dp[k][j|(1<<num[i][k-1]-1)] += dp[i][j]) %= mod;
                }
            }
        }
        int ans=0;
        F2(i, 0, n) {
            F2(j, 1, 20) (ans += dp[i][(1<<j)-1]) %= mod;
        }
        printf("%d", ans);
        return 0;
    }
    
    

    E. Bash Plays with Functions

    题意

    (f_0(n)):有序对((u,v))的个数,满足(u*v=n)(gcd(u,v)=1)
    (f_{r+1}(n)=sum_{u*v=n}frac{f_r(u)+f_r(v)}{2})

    给若干组询问(r,n),求(f_r(n))

    思路

    参考:http://www.cnblogs.com/candy99/p/6284051.html

    首先,(f_0(n))是什么?
    (n=p_1^{alpha_1}*p_2^{alpha_2}*cdots*p_k^{alpha_k}),则(u,v)的选取必然不能有相同的因子,所以情况必然是,(u)选择了一部分质数的所有次数,而(v)自然就选择了其他所有质数的所有次数。
    (f_0(n)=2^k).

    显然,(f_{r+1}(n)=sum_{u*v=n}frac{f_r(u)+f_r(v)}{2}=sum_{u|n}f_r(u)).
    因为(f_0)为积性函数,所以(f_r)为积性函数,所以$$f_r(n)=f_r(p_1{alpha_1}*p_2{alpha_2}cdotsp_k{alpha_k})=f_r(p_1{alpha_1})*f_r(p_2{alpha_2})*cdots*f_r(p_k{alpha_k})$$
    故只要求(f_r({p^alpha}))即可。

    [f_r({p^alpha})=f_r(1)+f_r(p)+f_r(p^2)+cdots+f_r(p^alpha) ]

    注意到,(f_0(p^alpha)=2)(p)无关,所以可用(dp[r][alpha])表示(f_r(p_alpha))(dp[r])(dp[r-1])的前缀和,预处理出即可。

    此外,线性筛时预处理出每个数的最小质因子,即可省得对每个(n)枚举因子。

    Code

    #include <bits/stdc++.h>
    #define F(i, a, b) for (int i = (a); i < (b); ++i)
    #define F2(i, a, b) for (int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for (int i = (a); i > (b); --i)
    #define dF2(i, a, b) for (int i = (a); i >= (b); --i)
    #define maxn 1000000
    #define maxk 20
    int dp[maxn+10][maxk+1], lp[maxn+10], prime[maxn], tot;
    bool vis[maxn+10];
    using namespace std;
    typedef long long LL;
    const LL mod=1e9+7;
    void init() {
        F2(i, 2, maxn) {
            if (!vis[i]) {
                prime[tot++] = i;
                lp[i] = i;
            }
            F(j, 0, tot) {
                if (i*prime[j]>maxn) break;
                vis[i*prime[j]] = true;
                lp[i*prime[j]] = prime[j];
                if (i%prime[j]==0) break;
            }
        }
        F2(i, 1, maxk) dp[0][i] = 2;
        F2(i, 1, maxn) {
            dp[i][0] = 1;
            F2(j, 1, maxk) dp[i][j] = (dp[i][j-1] + dp[i-1][j])%mod;
        }
    }
    LL calc(int n, int r) {
        LL ans=1;
        while (n>1) {
            int pr = lp[n], cnt=0;
            while (n % pr==0) ++cnt, n/=pr;
            (ans *= dp[r][cnt]) %= mod;
        }
        return ans;
    }
    int main() {
        init();
        int T;
        scanf("%d", &T);
        while (T--) {
            int n, r;
            scanf("%d%d", &r,&n);
            printf("%I64d
    ", calc(n, r));
        }
        return 0;
    }
    
    
  • 相关阅读:
    两个同心圆上的点一样多吗|一 一对应
    构造函数中的套路剖析
    开放性试题|发散思维
    初中数学静态思维导图01
    二轮复习中用题的特点和应对策略
    关注同理同法的重要性|思维+速度
    高中数学静态思维导图01
    同比与环比|题型
    初中数学静态思维导图02
    小学数学静态思维导图
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/8516637.html
Copyright © 2020-2023  润新知