zoukankan      html  css  js  c++  java
  • 清北学堂模拟赛d2t6 分糖果(candy)

    题目描述
    总共有n颗糖果,有3个小朋友分别叫做L,Y,K。每个小朋友想拿到至少k颗糖果,但这三个小朋友有一个共同的特点:对3反感。也就是说,如果某个小朋友拿到3颗,13颗,31颗,333颗这样数量的糖果,他就会不开心。(也即它拿到的糖果数量不包含有一位是3)
    LYK掌管着这n颗糖果,它想问你有多少种合理的分配方案使得将这n颗糖果全部分给小朋友且没有小朋友不开心。
    例如当n=3,k=1时只有1种分配方案,当n=4,k=1时有3种分配方案分别是112,121,211。当n=7,k=2时则不存在任何一种合法的方案。
    当然这个答案可能会很大,你只需输出答案对12345647取模后的结果就可以了。

    输入格式(candy.in)
    第一行两个数表示n,k。

    输出格式(candy.out)
    一个数表示方案总数。

    输入样例
    99999 1

    输出样例
    9521331

    对于30%的数据n<=100
    对于50%的数据n<=1000。
    对于另外30%的数据k=1。
    对于100%的数据3<=n<=10^10000,1<=k<=n/3,且n,k不包含前导0。

    分析:对于前50%的点,直接暴力枚举+判断就可以了.后50%的点数据和前50%的点数据规模完全不是一个数量级的,肯定要用不同的算法.数字肯定不能在时间复杂度里的,肯定是对数位进行处理,那么就要用到数位dp.

          这道题也不是一道特别简单的数位dp,因为要3个数的和等于n,所以我们可以在每一数位的时候枚举3个数上的这一位的值,它们的和与n的第i位相差是≤2的,因为进位最多进两位。同时还有≥k这个限制,所以我们可以设状态f[i][j][kk][l][p]表示前i位,第i+1位要向第i位进j位,kk,l,p表示枚举的3个数是否>k.每次递推的时候就能知道下一个状态,就能够就行转移了.

    要求方案数,数字位数又这么多,能想到的算法只有数位dp了,从数字看向数位,是一种很好的思想的转变,如果数位dp有数字大小的限制,那么通用的办法就是加一维表示是否超出限制即可.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int mod = 12345647;
    
    char n[10010], k[10010];
    int len1, len2,a[10010],b[10010],f[10010][3][2][2][2],ans;
    
    int main()
    {
        scanf("%s", n + 1);
        len1 = strlen(n + 1);
        scanf("%s", k + 1);
        len2 = strlen(k + 1);
        for (int i = 1; i <= len1; i++)
            a[i] = n[i] - '0';
        for (int i = 1; i <= len2; i++)
            b[i + len1 - len2] = k[i] - '0';
        f[0][0][0][0][0] = 1;
        for (int i = 0; i < len1; i++)
            for (int j = 0; j <= 2; j++)
                for (int k = 0; k <= 1; k++)
                    for (int l = 0; l <= 1; l++)
                        for (int p = 0; p <= 1; p++)
                            if (f[i][j][k][l][p])
                                for (int q = 0; q <= 9; q++)
                                    if (q != 3)
                                        for (int q2 = 0; q2 <= 9; q2++)
                                            if (q2 != 3)
                                                for (int q3 = 0; q3 <= 9; q3++)
                                                    if (q3 != 3)
                                                    {
                                                        int ni = i + 1, nj = j * 10 + a[i + 1] - q - q2 - q3;
                                                        int nk, nl, np;
                                                        if (nj < 0 || nj > 2)
                                                            continue;
                                                        if (k == 0 && q < b[ni])
                                                            continue;
                                                        nk = (k || q > b[ni]);
                                                        if (l == 0 && q2 < b[ni])
                                                            continue;
                                                        nl = (l || q2 > b[ni]);
                                                        if (p == 0 && q3 < b[ni])
                                                            continue;
                                                        np = (p || q3 > b[ni]);
                                                        f[ni][nj][nk][nl][np] += f[i][j][k][l][p];
                                                        if (f[ni][nj][nk][nl][np] >= mod)
                                                            f[ni][nj][nk][nl][np] -= mod;
                                                    }
        for (int i = 0; i <= 1; i++) //为什么要枚举0?因为我们排除了<k的情况,0就是=k的情况
            for (int j = 0; j <= 1; j++)
                for (int k = 0; k <= 1; k++)
                {
                    ans += f[len1][0][i][j][k];
                    if (ans >= mod)
                        ans -= mod;
                }
        printf("%d
    ", ans);
    
        return 0;
    }

     

  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7624720.html
Copyright © 2011-2022 走看看