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;
    }

     

  • 相关阅读:
    赤手空拳破解WINDOWS系统密码
    几扇鲜为人知的Windows XP自动运行后门
    Enumerating Logon Sessions
    用浏览器控件做界面,网页界面中定义自己的程序事件
    P2P之UDP穿透NAT的原理与实现(附源代码)
    delphi调用c#写的webservice中文出现乱码的问题
    基于Delphi的DirectShow开发概述
    视频捕获软件开发完全教学
    GINA 模块定义文件(Windows XP)
    GINA后门代码
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7624720.html
Copyright © 2011-2022 走看看