BZOJ 1026: [SCOI2009]windy数:
题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1026
dp[11][11][2]:dep,pre,f
要求的性质就是相邻数字差至少是2。
递归函数的状态设计如下dep,pre,f,分别表示已经枚举到第dep位,他的前一位(更高的位)是pre,f表示大小关系是否已经确定.
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=500000+50; #define mod 1000000007 #define inf 10000007 int dp[11][11][2],vis[11][11][2],d[11]; int dfs(int dep,int pre,int f) { if(dep<0) return 1; else if(pre>=0&&vis[dep][pre][f]) return dp[dep][pre][f]; else { int re=0; if(pre == -1) { re+=dfs(dep-1,-1,f||d[dep]>0); if(f) for(int i=1;i<=9;i++) re+=dfs(dep-1,i,1); else { for(int i=1;i<=d[dep];i++) { re+=dfs(dep-1,i,i<d[dep]); } } } else { if(f) { for(int i=0;i<10;i++) { if(abs(i-pre)>1) { re+=dfs(dep-1,i,1); } } } else { for(int i=0;i<10;i++) { if(i<=d[dep]&&abs(i-pre)>1) { re+=dfs(dep-1,i,i<d[dep]); } } } } if(pre>=0) vis[dep][pre][f]=1,dp[dep][pre][f]=re; return re; } } int cal(int n) { mem(dp);mem(vis); int len=0; while(n) { d[len++]=n%10;n/=10; } return dfs(len-1,-1,0); } int main() { int a,b; while(scanf("%d%d",&a,&b)!=EOF) { cout<<cal(b)-cal(a-1)<<endl; } return 0; }
BZOJ 3209: 花神的数论题:
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3209
求的是1到N内进制种类数的个数的乘积,显然是数学题嘛。。。。
仔细想想:我们如果只考虑二进制上01的个数,也就是如果枚举1的个数,将二进制上含有i个1的个数用数位dp求解出来,再算快速幂,就可以得到答案了
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=60+50; #define mod 10000007 #define inf 10000007 #define maxn 10000 ll dp[65][65][3],vis[65][65][3],d[N],c[N][N],ans[N];; ll dfs(int dep,int left,int f) { if(vis[dep][left][f]) return dp[dep][left][f]; if(dep+1<left) return 0;if(left==0) return 1; ll& re=dp[dep][left][f]; vis[dep][left][f]=1; if(!f) { if(d[dep]==0) { re+=dfs(dep-1,left,f); } else { re+=dfs(dep-1,left,1); re+=dfs(dep-1,left-1,0); } } else { re+=c[dep+1][left]; }//vis[dep][left][f]=1,dp[dep][left][f]=re; return re; } ll quick_pow(ll n,ll m) { ll ret=1; while(m) { if(m&1) ret=(ret*n)%mod; n=(n*n)%mod; m>>=1; } return ret; } ll cal(ll n) { int len=0;mem(vis);mem(dp); while(n) { d[len++]=n%2; n/=2; } for (int i=1;i<=len;i++) { ans[i]=dfs(len-1,i,0); } ll A=1; for(int i=2;i<=len;i++)A=(A*quick_pow(i,ans[i]))%mod; return A; } int main(){ ll n; for(int i=0;i<=60;i++) { c[i][0]=c[i][i]=1; for(int j=1;j<i;j++) { c[i][j]=c[i-1][j]+c[i-1][j-1]; } } while(scanf("%lld",&n)!=EOF) { printf("%lld ",cal(n)); } return 0; }
BZOJ 1799: [Ahoi2009]self 同类分布:
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1799
因为最多18位,最大也就是18*9,我们枚举位数和,去数位dp就可以了
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=600+50; #define mod 10000007 #define inf 10000007 #define maxn 10000 ll dp[20][200][200][2],vis[20][200][200][2]; int d[N]; ll dfs(int dep,int T,int f,int sum,int M) { if(dep<0) return T == 0 && sum == M; if(sum>M)return 0; if(vis[dep][T][sum][f]) return dp[dep][T][sum][f]; ll& re=dp[dep][T][sum][f]; vis[dep][T][sum][f]=1; if(f) { for(int i=0;i<=9;i++) { re+=dfs(dep-1,(T*10+i)%M,f,sum+i,M); } } else { for(int i=0;i<=d[dep];i++) { re+=dfs(dep-1,(T*10+i)%M,i<d[dep],sum+i,M); } } return re; } ll cal(ll x) { int len=0; ll A=0; while(x) d[len++]=x%10,x/=10; for(int i=1;i<=9*len;i++) { mem(dp),mem(vis); A+=dfs(len-1,0,0,0,i); } return A; } int main() { ll l,r; while(scanf("%I64d%I64d",&l,&r)!=EOF) { printf("%I64d ",cal(r)-cal(l-1)); //cout<<cal(r)-cal(l-1)<<endl; } return 0; }
HDU 4734 F(x):
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734
我们先求出F(A),题意只要求满足F(x)<=F(A) 的就行,所以我们从构造数位dp 将F(A)设为上限,
F(A)可以发现最大就是9*2^9多一点,我们再枚举一个数位大小的时候,将剩余上限减去使用当前数位的F()贡献
最后也就是枚举完,剩余>=0就可行
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=6000+50; #define mod 10000007 #define inf 10000007 #define maxn 10000 int dp[10][N],vis[10][N],d[20]; int dfs(int dep,int sum,int f) { if(sum<0) return 0; if(dep<0) return sum>=0; if(f&&vis[dep][sum]) return dp[dep][sum]; if(f) { int& re=dp[dep][sum]; vis[dep][sum]=1; for(int i=0;i<=9;i++) { re+=dfs(dep-1,sum-i*(1<<dep),f); } return re; } else { int re=0; for(int i=0;i<=d[dep];i++) { re+=dfs(dep-1,sum-i*(1<<dep),i!=d[dep]); } return re; } } int cal(int A,int B) { if(B==0) return 1; int sum=0;int len=0;//mem(dp),mem(vis); while(A) sum+=(A%10)*(1<<len),len++,A/=10; len=0; while(B) d[len++]=B%10,B/=10; return dfs(len-1,sum,0); } int main() { int T=read(); int A,B; for(int i=1;i<=T;i++) { A=read(),B=read(); printf("Case #%d: ",i); printf("%d ",cal(A,B)); } return 0; }
HDU 3555 Bomb:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555
求1到N内有49相连的数字个数,经典数位;
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=6000+50; #define mod 10000007 #define inf 10000007 #define maxn 10000 ll dp[60][60],vis[50][60],d[60]; ll dfs(int dep,int pre,int f) { if(dep<0) return 1; if(f&&vis[dep][pre]) return dp[dep][pre]; if(f) { ll& re=dp[dep][pre]; vis[dep][pre]=1; for(int i=0;i<=9;i++) { if(pre!=4||(pre==4&&i!=9)) { re+=dfs(dep-1,i,f); } }return re; } else { ll re=0; for(int i=0;i<=d[dep];i++) { if(pre!=4||(pre==4&&i!=9)) re+=dfs(dep-1,i,i<d[dep]); } return re; } } ll cal(ll x) { int len=0;mem(dp),mem(vis); while(x) d[len++]=x%10,x/=10; return dfs(len-1,0,0); } int main() { int T=read(); while(T--) { ll n; scanf("%I64d",&n); cout<<n-cal(n)+1<<endl; } return 0; }
HDU 3709 Balanced Number:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709
我们枚举平衡点就OK,注意0 的次数重复计算了,减去len-1就是答案
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x*f; } //**************************************** const int N=6000+50; #define mod 10000007 #define inf 10000007 #define maxn 10000 ll dp[20][6000][20],vis[20][6000][20],d[N]; ll dfs(int dep,int D,int mid,int f) { if(dep<0) return D==3000; if(f&&vis[dep][D][mid]) return dp[dep][D][mid]; if(f) { vis[dep][D][mid]=1; ll& re=dp[dep][D][mid]; for(int i=0;i<=9;i++) { re+=dfs(dep-1,D-(dep-mid)*i,mid,f); } return re; } else { ll re=0; for(int i=0;i<=d[dep];i++) { re+=dfs(dep-1,D-(dep-mid)*i,mid,i<d[dep]); } return re; } } ll cal(ll x) { if(x==0) return 1; if(x<0) return 0; int len=0;ll re=0;mem(dp),mem(vis); while(x) d[len++]=x%10,x/=10; for(int i=0;i<len;i++) { re+=dfs(len-1,3000,i,0); } return re-len+1; } int main() { int T=read(); while(T--) { ll l,r; scanf("%I64d%I64d",&l,&r); cout<<cal(r)-cal(l-1)<<endl; } return 0; }