转载请注明出处,谢谢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;
}
HDU 3709
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;
}