转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
HDU 3652
http://acm.hdu.edu.cn/showproblem.php?pid=3652
出现13,而且能被13整除。
加一维表示当前的余数。那么在后面加一位,余数被为(mod*10+i)%13。
递归的貌似好些点,不过应该在效率方面略差。细节处理貌似方便点。
详见代码注释
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<cmath> #include<algorithm> #define N 100005 #define inf 1<<29 #define MOD 9973 #define LL long long #define eps 1e-7 #define zero(a) fabs(a)<eps #define equal(a,b) zero(a-b) using namespace std; int dp[10][13][3]; //dp[i][j][k]表示i位数,对13的余数是j //k为0表示没有出现13 //k为1表示没有出现13,但是首位为3 //k为2表示出现13 int bit[15],len; //分别表示当前考虑的位置,前一个数字,当前余数,是否有限制,是否已经出现13 int dfs(int pos,int pre,int mod,bool limit,bool flag){ if(pos<=0) return flag&&(mod==0); //如果已经出现了13,而且余数为0,返回1,否则为0 if(!limit&&flag&&dp[pos][mod][0]!=-1) return dp[pos][mod][0]; //没有限制而且之前已经出现13,那么后面就随意 if(!limit&&!flag&&pre!=1&&dp[pos][mod][2]!=-1) return dp[pos][mod][2]; if(!limit&&!flag&&pre==1&&dp[pos][mod][1]!=-1) return dp[pos][mod][1]; //之前没有13,但是末位是1,那么后面的高位可以是3 int end=(limit?bit[pos]:9); int ret=0; for(int i=0;i<=end;i++) ret+=dfs(pos-1,i,(mod*10+i)%13,limit&&(i==end),flag||(pre==1&&i==3)); if(!limit){ if(pre==1&&!flag) dp[pos][mod][1]=ret; if(pre!=1&&!flag) dp[pos][mod][2]=ret; if(flag) dp[pos][mod][0]=ret; } return ret; } int slove(int n){ len=0; while(n){ bit[++len]=n%10; n/=10; } return dfs(len,0,0,true,false); } int main(){ int n; memset(dp,-1,sizeof(dp)); while(scanf("%d",&n)!=EOF) printf("%d\n",slove(n)); return 0; }
http://acm.hdu.edu.cn/showproblem.php?pid=3709
平衡数,枚举支点,然后其它的类似。加一维表示当前的力矩,注意当力矩为负时,就要返回,否则会出现下标为负,也算是个剪枝。
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<cmath> #include<algorithm> #define N 100005 #define inf 1<<29 #define MOD 9973 #define LL long long #define eps 1e-7 #define zero(a) fabs(a)<eps #define equal(a,b) zero(a-b) using namespace std; LL dp[20][20][2005]; //dp[i][j][k]表示考虑i位数字,支点为j,力矩和为k int bit[20],len; LL dfs(int pos,int central,int pre,bool limit){ if(pos<=0) return pre==0; // if(pre<0) return 0; //当前力矩为负,剪枝 if(!limit&&dp[pos][central][pre]!=-1) return dp[pos][central][pre]; int end=limit?bit[pos]:9; LL ret=0; for(int i=0;i<=end;i++) ret+=dfs(pos-1,central,pre+i*(pos-central),limit&&(i==end)); if(!limit) dp[pos][central][pre]=ret; return ret; } LL slove(LL n){ len=0; while(n){ bit[++len]=n%10; n/=10; } LL ans=0; for(int i=1;i<=len;i++) ans+=dfs(len,i,0,true); return ans-len+1; //除掉全0的情况,00,0000满足条件,但是重复了 } int main(){ LL l,r; int t; scanf("%d",&t); while(t--){ scanf("%I64d%I64d",&l,&r); memset(dp,-1,sizeof(dp)); printf("%I64d\n",slove(r)-slove(l-1)); } return 0; }