• bzoj 1974: [Sdoi2010]代码拍卖会


    Description

    随着iPig在P++语言上的造诣日益提升,他形成了自己一套完整的代
    码库。猪王国想参加POI的童鞋们都争先恐后问iPig索要代码库。iPi
    g不想把代码库给所有想要的小猪,只想给其中的一部分既关系好又
    肯出钱的小猪,于是他决定举行了一个超大型拍卖会。 在拍卖会上
    ,所有的N头小猪将会按照和iPig的好感度从低到高,从左到右地在i
    Pig面前站成一排。每个小猪身上都有9猪币(与人民币汇率不明),
    从最左边开始,每个小猪依次举起一块牌子,上面写上想付出的买代
    码库的猪币数量(1到9之间的一个整数)。大家都知道,如果自己付
    的钱比左边的猪少,肯定得不到梦寐以求的代码库,因此从第二只起
    ,每只猪出的钱都大于等于左边猪出的价钱。最终出的钱最多的小猪
    (们)会得到iPig的代码库真传,向着保送PKU(Pig Kingdom Unive
    rsity)的梦想前进。 iPig对自己想到的这个点子感到十分满意,在
    去现场的路上,iPig就在想象拍卖会上会出现的场景,例如一共会出
    现多少种出价情况之类的问题,但这些问题都太简单了,iPig早已不
    敢兴趣了,他想要去研究更加困难的问题。iPig发现如果他从台上往
    下看,所有小猪举的牌子从左到右将会正好构成一个N位的整数,他
    现在想要挑战的问题是所有可能构成的整数中能正好被P整除的有多
    少个。由于答案过大,他只想要知道答案mod 999911659就行了。
    Input
    一行:两个数N(1≤N≤10^18)、P(1≤P≤500),用一个空格分开。
    Output
    一行:一个数,表示答案除以999911659的余数。
    Sample Input
    2 3
    Sample Output
    15
    样例解释
    方案可以是:12 15 18 24 27 33 36 39 45 48 57 66 69 78 99,共15种。

    解题报告:

    这题真的可以玩死人啊,见过的最恶心,没有之一,首先要明白,这题中因为存在数列递增的性质,所以可以拆成1,11,111,1111,11111...中任意选9个以下的数字的和构成的数字,这也是此题给我的最大启发.
    然后就是DP,首先看数据范围我们只能从p下手,我们先预处理出1,11,111...中cnt[i]表示mod P后==i的数的个数,这个可以发现是循环的,处理完这里你就胜利了,DP十分简单,定义f[i][j][k] 表示已经处理到了前cnt[i],和mod P为j,一共用了k个数字的方案,容易看出f[i+1][(j+l×i)][k+l]=f[i][j][k]×C[cnt[i]+l-1][l],C[cnt[i]+l-1][l] 是从cnt[i]个中选出l个的可重组合方案

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    long long n;
    int k,f[505][10][505],dep[505],inv[10],c[505][10];
    long long cnt[505];
    long long p=999911659;
    int main()
    {    scanf("%lld%d",&n,&k);
        int s=0;
        cnt[0]++;
        int beg,len;
        if(n<=k)for(int i=1;i<=n;i++)cnt[s=(s*10+1)%k]++,cnt[s]%=p;
        else
        {    for(int i=1;i<=k+1;i++)
            {    s=(s*10+1)%k;
                if(cnt[s])
                {    beg=dep[s];
                    len=i-dep[s];
                    break;
                }
                cnt[s]++;
                dep[s]=i;
            }
            for(int i=0;i<k;i++)if(cnt[i]>0&&dep[i]>=beg)
            {    cnt[i]=(n-beg+1)/(long long)len%p;
                if((dep[i]-beg+1)<=(n-beg+1)%(long long)len)cnt[i]=(cnt[i]+1)%p;
                if((dep[i]-beg+1)%(long long)len==(n-beg+1)%(long long)len)s=i;
            }
        }
        inv[1]=1;
        for(int i=2;i<=8;i++)inv[i]=p-(long long)(p/i)*inv[p%i]%p;
        memset(f,0,sizeof 0);
        memset(c,0,sizeof c);
        for(int i=0;i<k;i++)
        {    c[i][0]=1;
            for(int j=1;j<=8;j++)
            {    c[i][j]=cnt[i]*c[i][j-1]%p*inv[j]%p;
                cnt[i]++;
                cnt[i]%=p;
            }
        }
        f[0][0][s]=1;
        for(int i=0;i<k;i++)
        {    for(int j=0;j<9;j++)
            {    for(int x=0;x<k;x++)
                {    for(int y=0;y<=j;y++)
                    {    f[i+1][j][x]=(f[i+1][j][x]+(long long)f[i][j-y][(x-y*i%k+k)%k]*c[i][y]%p)%p;
                    }
                }
            }
        }
        printf("%d
    ",f[k][8][0]);
        return 0;
    }
    
  • 相关阅读:
    面试题 16:反转链表
    Makefile学习之路6————通过函数增强功能
    Makefile学习之路5————变量
    Makefile学习之路3————规则的运行
    LED灯C语言的点亮方式
    LED灯汇编机器码的点亮方式
    Linux的进阶命令
    入门命令2
    shell命令解析器功能说明及入门命令1
    C++基础 — C++中的变量和三目运算符
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7429835.html
Copyright © 2020-2023  润新知