• BZOJ1799 [Ahoi2009]self 同类分布[数位DP]


    求出[a,b]中各位数字之和能整除原数的数的个数。

    困难的一道题。被迫看了题解:枚举每一个各位数字的和($<=162$),设计状态$f[len][sum][rest]$表示dp后面$len$位,要求这剩下的和是$sum$,并且其对$sum$取模是$rest$的方案数。

    感觉也讲不出什么道理来,真的是。。经验问题啊。。。当时数位dp不太会,现在看来稍微好些了。或者也可以从最高位往后看,设前面填好的高位组成的各位和是sum,mod枚举剩rest,到最低位再检验正确性。

    转移(向下一层dp)时就是把当前填的这一位数字从sum减掉,并且rest取$rest-i*10^{len-1}%p$,比如我一开始要求rest是0,第一位填3,后面的数要求的rest就变了。为什么是前面那个式子,这个可以推一下,很好推,就是剩余系相关的数学内容。然后每种sum都讨论一下,另外记搜可以带点剪枝什么的,卡卡就过啦。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define dbg(x) cerr<<#x<<" = "<<x<<endl
     7 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
     8 using namespace std;
     9 typedef long long ll;
    10 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    11 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    12 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    13 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    14 template<typename T>inline T read(T&x){
    15     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    16     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    17 }
    18 const ll bin[20]={0,1,10,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13,1e14,1e15,1e16,1e17,1e18};
    19 ll l,r,f[19][164][164],p;
    20 int flag,b[20];
    21 inline int mod(ll x){return x<0?x+p:x;}
    22 ll dp(int len,int s,int rest,bool limit){
    23     if(!len){if(!s&&!rest)return 1;else return 0;}
    24     if(s<0||9*len<s)return 0;//剪枝
    25     if(!limit&&~f[len][s][rest])return f[len][s][rest];
    26     int num=limit?b[len]:9;ll ret=0;
    27     for(register int i=0;i<=num;++i)ret+=dp(len-1,s-i,mod(rest-i*1ll*bin[len]%p),limit&&(i==num));
    28     return limit?ret:f[len][s][rest]=ret;
    29 }
    30 inline ll solve(ll x){
    31     ll k=0,ret=0;while(x)b[++k]=x%10,x/=10;
    32     for(p=1;p<=k*9;++p)memset(f,-1,sizeof f),ret+=dp(k,p,0,1);
    33     return ret;
    34 }
    35 
    36 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    37     read(l),read(r);if(l>=1e18)return printf("1
    "),0;if(r>=1e18)--r,++flag;
    38     return printf("%lld
    ",solve(r)-solve(l-1)+flag),0;
    39 }
  • 相关阅读:
    Action直接访问Servlet API
    Struts2与Struts1的对比
    参入github上的开源项目的步骤
    TortoiseSVN中图标的含义
    eclipse 快捷键
    base(function strchr)
    1
    Java 关于路径
    java初阶
    关于C++中计时的方法
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10668593.html
Copyright © 2020-2023  润新知