## P4127 同类分布
现在关键的问题是:怎样记录dp状态?
这里 st可达到 1e18 显然是不能作为dp转移的下标直接记录的
所以我们考虑取模
我们最理想的模数当然是把每次搜到最后得到的数字各个位数之和
但是我们发现在这个过程中 sum是发生变化的
所以我们就应该以一个定值作为模数
那好,我们虽然不知道最后各位之和的结果,我们枚举总可以吧
我们只需要枚举所有的各位数字之和作为模数
最后判断 sum 和枚举的 mod相等并且 st%sum=0 的数就是符合题意的答案
/*
reference:
https://www.luogu.org/blog/virus2017/p4127#
date:
2019.10.03
solution:
- 既然st的范围是1e18那么long long都存不下肯定不能记为dp的状态
- 那么肯定要取模!模数为什么呢 ?最好为当前模数和sum
- 可是sum在转移的时候一直在改变,那么之前记录的dp状态就无效了!
- 那我们换个思路,模数呢最大为18*9,那我们枚举每个模数,判断当前在这个模数意义下是否合法
- 合法的条件:sum==mod && st==0(st要一直%mod)
*/
int a,b,len,mod;
int dp[18+5][18*9+5][18*9+5],bit[18+5];
inline int dfs(int pos,int sum,int st,int limit){
if(pos>len && sum==0)return 0;
if(pos>len)return sum==mod && st==0;
if(!limit && dp[pos][sum][st]!=-1)return dp[pos][sum][st];
int high=limit?bit[len-pos+1]:9;
int res=0;
rep(i,0,high){
res+=dfs(pos+1,sum+i,(10ll*st+i)%mod,i==high && limit);
}
// return limit?res:dp[pos][sum][st]=res;
if(!limit)dp[pos][sum][st]=res;
return res;
}
inline int work(int x){
len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
int res=0;
for(mod=1;mod<=len*9;++mod){
mem(dp,-1);
res+=dfs(1,0,0,1);
}
return res;
}
#undef int
int main(){
#define int long long
freopen("tonglei.txt","r",stdin);
rd(a),rd(b);
printf("%lld",work(b)-work(a-1));
return 0;
}
##windy数
/*
reference:
https://www.luogu.org/blog/virus2017/solution-p2657
date:
2019.10.03
solution:
最妙:考虑前导零的时候,第一位的时候,0和1是没办法取到的,因为abs(i-pre)<2了,
那么,就等价于,pre设为-2问题解决
*/
int a,b,len;
int bit[15],dp[15][15];
inline int dfs(int pos,int pre,int lead,int limit){
if(pos>len)return 1;
if(!limit && dp[pos][pre]!=-1)return dp[pos][pre];
int high=limit?bit[len-pos+1]:9;
int res=0;
rep(i,0,high){
if(abs(i-pre)<2)continue;
else if(lead && i==0)
res+=dfs(pos+1,-2,1,i==high && limit);
else
res+=dfs(pos+1,i,0,i==high && limit);
}
if(!limit && !lead)dp[pos][pre]=res;
return res;
}
inline int work(int x){
len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
mem(dp,-1);
return dfs(1,-2,1,1);
}
#undef int
int main(){
#define int long long
#ifdef WIN64
freopen("windy.txt","r",stdin);
#endif
rd(a),rd(b);
printf("%lld\n",work(b)-work(a-1));
return 0;
}
##数字计数(求不降数)
/*
int a,b,len,mod;
int bit[15],dp[15][15];
inline int dfs(int pos,int pre,int limit){
if(pos>len)return 1;
if(dp[pos][pre]!=-1 && !limit)return dp[pos][pre];
int high=limit?bit[len-pos+1]:9;
int res=0;
rep(i,pre,high){
res+=dfs(pos+1,i,i==high && limit);
}
if(!limit)dp[pos][pre]=res;
return res;
}
inline int work(int x){
len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
mem(dp,-1);
return dfs(1,0,1);
}
#undef int
int main(){
#define int long long
#ifdef WIN64
freopen("shuzi2.txt","r",stdin);
#endif
while(~scanf("%lld%lld",&a,&b)){
printf("%lld\n",work(b)-work(a-1));
}
return 0;
}
##不要62
/*
int a,b,len;
int bit[10],dp[10][15];
inline int dfs(int pos,int pre,int limit){
if(pos>len)return 1;
if(dp[pos][pre]!=-1 && !limit)return dp[pos][pre];
int high=limit?bit[len-pos+1]:9;
int res=0;
rep(i,0,high){
if(i==4)continue;
if(pre==6 && i==2)continue;
res+=dfs(pos+1,i,i==high && limit);
}
if(!limit)dp[pos][pre]=res;
return res;
}
inline int work(int x){
mem(bit,0);
len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
mem(dp,-1);
return dfs(1,0,1);
}
#undef int
int main(){
#define int long long
#ifdef WIN64
freopen("62.txt","r",stdin);
#endif
while(1){
rd(a),rd(b);
if(a==0 && b==0)break;
printf("%lld\n",work(b)-work(a-1));
}
return 0;
}
##数字游戏(取模)
int a,b,len,mod;
int bit[15],dp[15][900];
inline int dfs(int pos,int sum,int limit){
if(pos>len)return sum==0?1:0;
if(!limit && dp[pos][sum]!=-1)return dp[pos][sum];
int high=limit?bit[len-pos+1]:9;
int res=0;
rep(i,0,high){
res+=dfs(pos+1,(sum+i)%mod,i==high && limit);
}
if(!limit)dp[pos][sum]=res;
return res;
}
inline int work(int x){
len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
mem(dp,-1);
return dfs(1,0,1);
}
#undef int
int main(){
#define int long long
#ifdef WIN64
freopen("shuzi.txt","r",stdin);
#endif
while(~scanf("%lld%lld%lld",&a,&b,&mod)){
printf("%lld\n",work(b)-work(a-1));
}
return 0;
}
原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11634654.html
时间: 2024-10-29 00:06:23