• Bzoj1974 [Sdoi2010]auction 代码拍卖会


    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 375  Solved: 151

    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种。
    数据规模
    测试点 N P 测试点 N P
    1 ≤1000 ≤500 6 ≤10^6 ≤500
    2 ≤10^18 5 7 ≤10^18 ≤120
    3 ≤10^18 ≤10 8 ≤10^18 ≤500
    4 ≤10^18 ≤10 9 ≤10^18 ≤500
    5 ≤10^18 25 10 ≤10^18 ≤500

    HINT

     

    Source

    动规 分组背包

    好题,神题,神到让人心生绝望。

    首先要知道利用数列中数字不减小的性质能做点什么。

    ——可以根据这一性质把数列拆成:

      0

      1

      11

      111

      1111

      ...

      11111111111

    这些数中任取9个累加的形式。

    而这些全由1构成的数有一个特殊性质:随着1个数的递增,它们模一个数的结果会构成循环。那些直接想到的人有多强

    那么就可以算出余数相同的数有多少个,将问题转化成分组背包

    同一组中的数的效果等价,所以累加方案的时候算组合数就可以,组合数当然不能递推咯,需要用公式算。模意义下组合数公式需要乘逆元,而逆元不能用公式算(复杂度太高),那就需要递推咯

    ---逆元递推---

    inv[1]=1

    for(int i=2;i<=9;i++){inv[i]=((-(mod/i)*inv[mod%i])%mod+mod)%mod;}

    ----

    A掉之后我在想,如果70行不用memset,而是直接继承上一次的状态,会不会更快一点 (如71-75行)?

      ↑但改成那样写之后反而WA了,发现是79行算完的结果没有就地取mod

        ↑那我之前是怎么AC的

          ↑玄学

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #define LL long long
     8 using namespace std;
     9 const int mod=999911659;
    10 const int mxn=1010;
    11 LL f[2][10][501]; 
    12 LL n;int m;
    13 LL cnt[mxn],w[mxn];
    14 LL c[mxn][mxn];
    15 LL inv[mxn];
    16 int add,ans;
    17 void Inv_init(){//逆元 
    18     inv[1]=1;
    19     for(int i=2;i<=9;i++){inv[i]=((-(mod/i)*inv[mod%i])%mod+mod)%mod;}
    20     for(int i=2;i<9;i++)inv[i]=inv[i]*inv[i-1]%mod;
    21     return;
    22 }
    23 LL clc(LL u,LL d){//组合数 
    24     if(!d)return 1;
    25     if(d>u)return 0;
    26     LL res=1;
    27     for(LL i=u-d+1;i<=u;i++)res=res*(i%mod)%mod;
    28     res=res*inv[d]%mod;
    29     return res;
    30 }
    31 int main(){
    32     int i,j;
    33     scanf("%lld%d",&n,&m);
    34     Inv_init();
    35     LL x=1%m;//%k以排除k==1的情况 
    36     int tot=0;
    37     while(!cnt[x]){//寻找循环节 
    38         cnt[x]=++tot;w[tot]=x;
    39         if(tot>=n)break;
    40         x=(x*10+1)%m;
    41     }
    42     if(tot<n){//出现循环
    43         LL len=n-cnt[x]+1;//剩余长度 
    44         int sz=tot-cnt[x]+1;//循环部分长度 
    45         if(sz>1)
    46             add=(m-w[cnt[x]+((len%sz)?len%sz:sz)-1])%m;
    47         else add=(m-w[cnt[x]])%m;
    48          
    49         int tmp=cnt[x];
    50         for(i=0;i<m;i++){
    51             if(cnt[i]){
    52                 if(cnt[i]<tmp)cnt[i]=1;//未循环部分单独分组
    53                 else if(sz>1 && (len%sz)>cnt[i]-tmp)cnt[i]=len/sz+1;
    54                     else cnt[i]=len/sz;
    55             }
    56         }
    57     }
    58     else{//若n个数不构成循环 
    59         add=(m-x)%m;
    60         for(i=0;i<m;i++)if(cnt[i])cnt[i]=1;
    61     }
    62     for(i=0;i<m;i++)
    63         if(cnt[i])  for(j=0;j<9;j++) c[i][j]=clc(cnt[i]+j-1,j);
    64  
    65     f[0][0][0]=1;
    66     int tmp=0;
    67     for(i=0;i<m;i++){
    68         if(cnt[i]){
    69             tmp^=1;
    70             memset(f[tmp],0,sizeof f[tmp]);
    71 /*          for(j=0;j<9;j++){
    72                 for(int k=0;k<m;k++){
    73                     f[tmp][j][k]=f[tmp^1][j][k];
    74                 }
    75             }*/
    76             for(j=0;j<9;j++){
    77                 for(int k=0;k<m;k++){
    78                     for(int l=0;l<9-j;l++){
    79                         (f[tmp][j+l][(k+l*i)%m]+=f[tmp^1][j][k]*c[i][l]%mod)%=mod;
    80                     }
    81                 }
    82             }
    83         }
    84     }
    85     for(i=0;i<9;i++)ans=(ans+f[tmp][i][add])%mod;
    86     printf("%d
    ",ans);
    87     return 0;
    88 }
    本文为博主原创文章,转载请注明出处。
  • 相关阅读:
    vue---echarts图表
    路由嵌套
    VoIP语音通话研究【进阶篇(四):freeswitch+webrtc+sip.js的通话】
    VoIP语音通话研究【进阶篇(三):opensips安装】
    如何在北京退休?
    后端分析/前端分析/边缘分析
    使用curl批量下载图片
    pytorch固定随机种子复现实验结果
    分享一个作为面试官的面试思路
    两个流程链路问题的排查和总结
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6485503.html
Copyright © 2020-2023  润新知