1. 程式人生 > >洛谷 - P2602 - [ZJOI2010]數字計數 - 數位dp

洛谷 - P2602 - [ZJOI2010]數字計數 - 數位dp

amp 一次循環 怎麽 class pri 不同 out %d 核心

https://www.luogu.org/problemnew/show/P2602

第二道數位dp,因為“數位dp都是模板題”(誤),所以是從第一道的基礎上面改的。

核心思想就是分類討論,分不同情況討論對答案的貢獻。

最最重要的是,該數位取與當前位相等的時候,貢獻的個數是受這個數位影響的所有數(這個寫法裏包括它本身),那麽就用x減去與x前綴相同的“整數”再+1就可以算出來了。

其他的數位dp……好像就不太會寫了,再研究一下。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[14][10][10];
ll pow10[
14]; ll sum(int i,int j1,int j2,int k){ if(j1<0) j1=0; if(j2>9) j2=9; ll res=0; for(int j=j1;j<=j2;j++){ res+=dp[i][j][k]; } return res; } void init(){ pow10[0]=1; for(int i=1;i<=13;i++){ pow10[i]=pow10[i-1]*10; } for(int
j=0;j<=9;j++) dp[1][j][j]=1; for(int i=2;i<=13;i++){ for(int j=0;j<=9;j++){ for(int k=0;k<=9;k++){ dp[i][j][k]=sum(i-1,0,9,k); if(j==k){ dp[i][j][k]+=pow10[i-1]; } } } }
/*for(int j=1;j<=2;j++){ dp[9][j]=sum(8,0,j-2)+sum(8,j+2,9); }*/ /*for(int i=1;i<=13;i++){ for(int j=0;j<=9;j++){ for(int k=0;k<=9;k++) printf("dp[%d][%d][%d]=%d\n",i,j,k,dp[i][j][k]); } printf("\n"); }*/ } ll A,B; int digit[14]; int w; ll count(ll x){ //cout<<"x="<<x<<endl; if(x<0) return 0; if(x==0){ if(w==0) return 1; else return 0; } //否則豈不是0位數? ll k=0,cx=x; digit[k++]=0; //占位用的 while(cx){ digit[k++]=cx%10; cx/=10; } k--; digit[k+1]=0; //也是占位 ll res=0; for(int i=k;i>=1;i--){ //printf("i=%d res=%d\n",i,res); if(i==k){ //最高位取0 for(int ii=i-1;ii>=1;ii--){ res+=sum(ii,1,9,w); //printf("you want=%d\n",res); } if(w==0) res+=1;//0 //其實不用特判啊 for(int j=1;j<digit[i];j++){ //最高位比digit小且不為0 if(i-1>=1){ if(j==w) res+=pow10[i-1]; res+=sum(i-1,0,9,w); } else{ if(j==w) res+=1; } } //最高位就取相等,問題留給下一次循環 //取相等怎麽會是滿的呢? if(digit[i]==w) res+=(x-x/pow10[i-1]*pow10[i-1]+1); } else{ //前面的位都相等,非最高位的情況 for(int j=0;j<digit[i];j++){ if(i-1>=1){ if(j==w) res+=pow10[i-1]; res+=sum(i-1,0,9,w); } else{ if(j==w) res+=1; } } if(digit[i]==w) res+=(x-x/pow10[i-1]*pow10[i-1]+1); } } //一直相等的情況在上面自動處理了,不用另外處理 /*for(int i=1;i<=k;i++){ if(digit[i]==w){ res++; } }*/ //printf("res=%d\n",res); return res; } int main(){ init(); while(~scanf("%lld%lld",&A,&B)){ for(w=0;w<=9;w++) printf("%lld%c",count(B)-count(A-1)," \n"[w==9]); } }

洛谷 - P2602 - [ZJOI2010]數字計數 - 數位dp