(难度C-D-E-G-H-A-F-B-J)
数位dp整体思路就是确立状态开始dfs
注意
大部分情况memset -1 比较快
大部分情况memset只执行1次
digit这一维大部分情况下可以省掉
A-cf55D
题解:
题意大致是求 [ l , r ] [l,r] [l,r]区间内各个位上的数都是其因子的个数。
考虑 d p [ l e n ] [ d i g i t ] [ p r e ] [ n u m 2 ] [ n u m 3 ] [ n u m 5 ] [ n u m 7 ] dp[len][digit][pre][num2][num3][num5][num7] dp[len][digit][pre][num2][num3][num5][num7]
p r e pre pre记录其值 m o d ( 8 ∗ 9 ∗ 5 ∗ 7 ) mod(8*9*5*7) mod(8∗9∗5∗7)的值, n u m 2 num2 num2代表因子 2 2 2的个数, n u m 3 num3 num3代表因子 3 3 3的个数……
在len==1是我们只要看pre这个数是否符合有后四维的情况即可
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[20][10][2530][4][3][2][2],num[21];
ll dfs(int len,int digit,bool up,int pre,int num_2,int num_3,int num_5,int num_7){
if(len==1){
int tmp=1;
//cout<<pre<<' ';
for(int i=1;i<=num_2;i++) tmp*=2;
for(int i=1;i<=num_3;i++) tmp*=3;
for(int i=1;i<=num_5;i++) tmp*=5;
for(int i=1;i<=num_7;i++) tmp*=7;
//cout<<tmp<<endl;
if(pre%tmp==0) return 1;
else return 0;
}
if(dp[len][digit][pre][num_2][num_3][num_5][num_7]!=-1&&!up) return dp[len][digit][pre][num_2][num_3][num_5][num_7];
ll res=0;
int num2=num_2,num3=num_3,num5=num_5,num7=num_7;
for(int i=0;i<=(up?num[len-1]:9);i++){
if(i==2) num_2=max(1,num_2);
else if(i==3) num_3=max(1,num_3);
else if(i==4) num_2=max(2,num_2);
else if(i==5) num_5=1;
else if(i==6) {num_2=max(1,num_2);num_3=max(1,num_3);}
else if(i==7) num_7=1;
else if(i==8) num_2=3;
else if(i==9) num_3=2;
if(up&&i==num[len-1]) res+=dfs(len-1,i,1,(pre*10+i)%2520,num_2,num_3,num_5,num_7);
else res+=dfs(len-1,i,0,(pre*10+i)%2520,num_2,num_3,num_5,num_7);
num_2=num2,num_3=num3,num_5=num5,num_7=num7;
}
if(!up) dp[len][digit][pre][num_2][num_3][num_5][num_7]=res;
return res;
}
ll solve(ll x){
ll ans=0;
int tot=0;
while(x){
num[++tot]=x%10;
x/=10;
}
num[tot+1]=0;
ans=dfs(tot+1,0,1,0,0,0,0,0);
return ans;
}
int main(){
int t;
ll n,m;
cin>>t;
memset(dp,-1,sizeof(dp));
while(t--){
cin>>n>>m;
cout<<solve(m)-solve(n-1)<<endl;
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
B-HDU4352
题解:
题意大致是让你求[l,r]区间其LIS刚好为k的个数。
这里一开始往建立10!的数组去维护最后一位是i的LIS值(肯定T且存不下)
之后想这nlogn的LIS求法中找到启发,即只要维护一个递增的数列即可,且数列个数不超过10 这样就可以用 2 n 2^n 2n, n = 10 n=10 n=10的状态去表示这个数列。
即可得到一个这样的状态dp[20][4086][11]即可求解。
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[22][2050][12],num[22];
int k;
ll dfs(int len,bool up,int pre,bool zero){
if(len==1){
if(zero&&k==1) return 1;
int tmp=0;
for(int i=1;i<=10;i++){
if(pre&(1<<(i-1))) tmp++;
}
if(tmp==k) return 1;
return 0;
}
if(dp[len][pre][k]!=-1&&!up&&!zero) return dp[len][pre][k];
ll res=0;
for(int i=0;i<=(up?num[len-1]:9);i++){
int zj=-1;
for(int j=i;j<=9;j++){
if(pre&(1<<(j))){
zj=j;
break;
}
}
if(!up||(up&&i==num[len-1])){
if(i>0||!zero)
res+=dfs(len-1,up,zj!=-1?pre-(1<<zj)+(1<<i):pre+(1<<i),0);
else
res+=dfs(len-1,up,pre,1);
}
else {
if(i>0||!zero)
res+=dfs(len-1,!up,zj!=-1?pre-(1<<zj)+(1<<i):pre+(1<<i),0);
else
res+=dfs(len-1,!up,pre,1);
}
}
//cout<<len<<' '<<pre<<' '<<res<<endl;
if(!zero&&!up){
dp[len][pre][k]=res;
}
return res;
}
ll solve(ll x){
int tot=0;
if(x==0&&k==1) return 1;
else if(x==0&&k!=1) return 0;
while(x){
num[++tot]=x%10;
x/=10;
}
return dfs(tot+1,1,0,1);
}
int main(){
//freopen("1.txt","r",stdin);
ll n,m;
int t;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
for(int i=1;i<=t;i++){
scanf("%lld%lld%d",&n,&m,&k);
printf("Case #%d: %lld\n",i,solve(m)-solve(n-1));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
C HDU2089
裸的数位dp
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
int dp[20][20];
int Len,num[20];
int solve(int len,int digit,bool up){
int res=0;
if(digit==4||len<=0) return 0;
if((len==1||!up)&&dp[len][digit]) return dp[len][digit];
//cout<<num[len-1]<<"----"<<endl;
for(int i=0;i<=(up?num[len-1]:9);i++){
if(digit==6&&i==2) continue;
//cout<<i<<endl;
if((up&&i==num[len-1])||!up) res+=solve(len-1,i,up);
else res+=solve(len-1,i,!up);
}
if(!up){
dp[len][digit]=res;
}
//cout<<len<<' '<<digit<<' '<<up<<' '<<res<<endl;
return res;
}
int cla(int x){
int tot=0,ans=0;
if(x==0) return 1;
while(x){
num[++tot]=x%10;
x/=10;
}
memset(dp,0,sizeof(dp));
for(int i=0;i<=9;i++){
dp[1][i]=1;
}
for(int i=0;i<=num[tot];i++){
if(i==num[tot]) ans+=solve(tot,i,1);
else ans+=solve(tot,i,0);
}
return ans;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
printf("%d\n",cla(m)-cla(n-1));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
D HDU3555
裸体
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
int dp[20][20];
int Len,num[20];
int solve(int len,int digit,bool up){
int res=0;
if(digit==4||len<=0) return 0;
if((len==1||!up)&&dp[len][digit]) return dp[len][digit];
//cout<<num[len-1]<<"----"<<endl;
for(int i=0;i<=(up?num[len-1]:9);i++){
if(digit==6&&i==2) continue;
//cout<<i<<endl;
if((up&&i==num[len-1])||!up) res+=solve(len-1,i,up);
else res+=solve(len-1,i,!up);
}
if(!up){
dp[len][digit]=res;
}
//cout<<len<<' '<<digit<<' '<<up<<' '<<res<<endl;
return res;
}
int cla(int x){
int tot=0,ans=0;
if(x==0) return 1;
while(x){
num[++tot]=x%10;
x/=10;
}
memset(dp,0,sizeof(dp));
for(int i=0;i<=9;i++){
dp[1][i]=1;
}
for(int i=0;i<=num[tot];i++){
if(i==num[tot]) ans+=solve(tot,i,1);
else ans+=solve(tot,i,0);
}
return ans;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
printf("%d\n",cla(m)-cla(n-1));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
E POJ-3252
题解:
记录一维0的个数记录一维1的个数即可
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[66][3][66][66],num[66];
ll dfs(int len,int digit,bool up,bool pre,int numb,int pp){
if(len==1){
//cout<<numb<<' '<<pp<<' '<<digit<<endl;
if(numb*2<=pp) return 1;
else return 0;
}
ll res=0;
if(dp[len][digit][numb][pp]&&!up) return dp[len][digit][numb][pp];
for(int i=0;i<=(up?num[len-1]:1);i++){
if(up&&i==num[len-1]){
res+=dfs(len-1,i,up,0,numb+i,pp+1);
}
else if(!up){
if(!pre) res+=dfs(len-1,i,up,pre,numb+i,pp+1);
else {
if(i==1){
res+=dfs(len-1,i,up,0,numb+i,pp+1);
}
else {
res+=dfs(len-1,i,up,1,numb,pp);
}
}
}
else {
res+=dfs(len-1,i,!up,0,numb+i,pp+1);
}
}
if(!up){
dp[len][digit][numb][pp]=res;
}
return res;
}
ll solve(ll x){
ll ans=0;
int tot=0;
if(x==0) return 1;
memset(dp,0,sizeof(dp));
while(x){
num[++tot]=x%2;
x/=2;
}
ans+=dfs(tot,1,1,0,1,1);
ans+=dfs(tot,0,0,1,0,0);
/*for(int i=1;i<=tot;i++){
for(int j=0;j<=tot;j++){
for(int p=j;p<=tot;p++){
cout<<i<<' '<<j<<' '<<p<<endl;
cout<<dp[i][0][j][p]<<' '<<dp[i][1][j][p]<<endl;
}
}
}*/
//cout<<ans<<endl;
return ans;
}
int main(){
ll n,m;
cin>>n>>m;
cout<<solve(m)-solve(n-1)<<endl;
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
F HDU-3709
题解:
存一维中轴 一维和(中轴左为+右为-)这样这要开 5000 5000 5000大小就绰绰有余
我的 d p dp dp状态是 d p [ 21 ] [ 21 ] [ 4000 ] [ 2 ] [ 2 ] dp[21][21][4000][2][2] dp[21][21][4000][2][2] 后 2 2 2维其实可以省掉
(在这里学会了 m e m s e t memset memset只需执行 1 1 1次即可,不然会 T T T)
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[21][21][4001][2][2];
ll num[21];
ll dfs(int len,bool up,int pre,int mi,bool zero){
ll res=0;
if(len==1){
if(pre==2000) return 1;
else return 0;
}
if(!zero&&len-1<mi) return 0;
if(!up&&dp[len][mi][pre][zero][0]!=-1&&mi>len) return dp[len][mi][pre][zero][0];
if(!up&&dp[len][mi][pre][zero][1]!=-1&&mi<=len) return dp[len][mi][pre][zero][1];
for(int i=0;i<=(up?num[len-1]:9);i++){
if(i>=1) zero=true;
if(up){
//cout<<"YES"<<endl;
if(i==num[len-1]) res+=dfs(len-1,up,pre+(len-1-mi)*i,mi,zero);
else res+=dfs(len-1,!up,pre+(len-1-mi)*i,mi,zero);
}
else res+=dfs(len-1,up,pre+(len-1-mi)*i,mi,zero);
}
if(!up){
if(mi>len)
dp[len][mi][pre][zero][0]=res;
else
dp[len][mi][pre][zero][1]=res;
}
return res;
}
ll solve(ll x){
int tot=0;
ll ans=0;
if(x<0) return 0;
else if(x==0) return 1;
while(x){
num[++tot]=x%10;
x/=10;
}
for(int i=1;i<=tot;i++){
ans+=dfs(tot+1,1,2000,i,0);
}
return ans;
}
int main(){
//freopen("1.txt","r",stdin);
int t;
ll n,m;
memset(dp,-1,sizeof(dp));
scanf("%d",&t);
while(t--){
scanf("%I64d%I64d",&n,&m);
printf("%I64d\n",solve(m)-solve(n-1));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
G HDU-3652
裸体
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[20][11][20][3];
int num[20];
ll dfs(int len,int digit,bool up,int pre,bool mark){
ll res=0;
if(len==1){
if(pre==0&&mark) return 1;
else return 0;
}
if(!up&&dp[len][digit][pre][mark]!=-1) return dp[len][digit][pre][mark];
for(int i=0;i<=(up?num[len-1]:9);i++){
bool tmp=mark;
if(digit==1&&i==3) tmp=true;
if(up){
if(i==num[len-1]) res+=dfs(len-1,i,up,(pre*10+i)%13,tmp);
else res+=dfs(len-1,i,!up,(pre*10+i)%13,tmp);
}
else res+=dfs(len-1,i,up,(pre*10+i)%13,tmp);
}
if(!up){
dp[len][digit][pre][mark]=res;
}
return res;
}
ll solve(ll x){
int tot=0;
ll ans=0;
while(x){
num[++tot]=x%10;
x/=10;
}
memset(dp,-1,sizeof(dp));
for(int i=0;i<=num[tot];i++){
if(i==num[tot]) ans+=dfs(tot,i,1,i,0);
else ans+=dfs(tot,i,0,i,0);
}
return ans;
}
int main(){
ll n;
while(~scanf("%lld",&n)){
printf("%lld\n",solve(n));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
H HDU-4734
题解:
d
p
[
p
o
s
]
[
n
u
m
]
dp[pos][num]
dp[pos][num] 表示在该位上比
n
u
m
num
num小的数的个数
即可写出如下转移
d
p
[
p
o
s
]
[
n
u
m
]
=
dp[pos][num]=
dp[pos][num]=
∑
\sum
∑
d
p
[
p
o
s
−
1
]
[
n
u
m
−
d
i
g
i
t
∗
(
1
<
<
(
p
o
s
−
1
)
)
]
dp[pos-1][num-digit*(1<<(pos-1))]
dp[pos−1][num−digit∗(1<<(pos−1))]
之后就是正常的数位dp过程
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[11][10000],num[11];
ll dfs(int len,int numb,bool up){
if(numb<0) return 0;
if(len==0) return 1;
if(dp[len][numb]!=-1&&!up) return dp[len][numb];
ll res=0;
for(int i=0;i<=(up?num[len]:9);i++){
if(up&&i==num[len])
res+=dfs(len-1,numb-i*(1<<(len-1)),1);
else
res+=dfs(len-1,numb-i*(1<<(len-1)),0);
}
if(!up){
dp[len][numb]=res;
}
return res;
}
ll solve(ll x,ll y){
int tot=0;
ll ans=0;
while(x){
num[++tot]=x%10;
x/=10;
}
ll maxn=0;
ll p=1;
while(y){
maxn+=p*(y%10);
p*=2LL;
y/=10;
}
//memset(dp,-1,sizeof(dp));
//cout<<tot<<' '<<maxn<<endl;
ans=dfs(tot,maxn,1);
return ans;
}
int main(){
int t;
int ti=0;
ll a,b;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
while(t--){
scanf("%lld%lld",&a,&b);
printf("Case #%d: %lld\n",++ti,solve(b,a));
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
J HDU-4507
题解:
此题不让我们计数 而是让我求所有可行数的平方和
这类问题还是可以用数位dp解决(平方和与和、个数有关)
令个数为ant,和为sum,平方和为squre
因为我们可以发现在统计到pos位时 pos-1位的所有数的和是可以求出来的
sum[pos]=sum[pos-1]+digit*10^(pos-1)*ant[pos-1]
平方和又可以展开成
s q u r e [ p o s ] squre[pos] squre[pos]= ( ( d i g i t ∗ 1 0 ( p o s − 1 ) ) 2 ∗ a n t [ p o s − 1 ] ((digit*10^(pos-1))^2*ant[pos-1] ((digit∗10(pos−1))2∗ant[pos−1]+ 2 ∗ s u m [ p o s − 1 ] ∗ d i g i t ∗ 1 0 ( p o s − 1 ) + s q u r e [ p o s − 1 ] 2*sum[pos-1]*digit*10^(pos-1)+squre[pos-1] 2∗sum[pos−1]∗digit∗10(pos−1)+squre[pos−1]
(可以尝试推一推)
(比较坑的是容易爆long long 所以处理好mod即可)
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll num[20];
ll mul(ll x,ll y){
return ((x)%mod)*((y)%mod)%mod;
}
struct node{
ll ant;
ll sum;
ll squar;
void INIT(){
ant=-1;
sum=0;
squar=0;
}
void init(){
ant=sum=squar=0;
}
}dp[20][10][8][8];
ll P[22];
node dfs(int len,ll digit,bool up,int pre,int pre_){
node res,Next;
res.init();
//cout<<res.squar<<res.ant<<res.sum<<endl;
if(len==1){
if(pre!=0&&pre_!=0&&digit!=7) {
res.ant=1;
res.sum=digit;
res.squar=digit*digit;
return res;
}
else return res;
}
if(dp[len][digit][pre][pre_].ant!=-1&&!up) return dp[len][digit][pre][pre_];
for(ll i=0;i<=(up?num[len-1]:9);i++){
//cout<<len<<' '<<i<<endl;
if(i==7) continue;
if(up){
if(i==num[len-1]) Next=dfs(len-1,i,up,(pre+i)%7,(pre_*10+i)%7);
else Next=dfs(len-1,i,!up,(pre+i)%7,(pre_*10+i)%7);
}
else Next=dfs(len-1,i,up,(pre+i)%7,(pre_*10+i)%7);
res.ant+=Next.ant;
//res.sum+=(next.ant*((digit*P[len-1])%mod))%mod;
res.sum+=(mul(mul(1LL,Next.ant),mul(digit,P[len-1])));
res.sum%=mod;
res.sum+=Next.sum;
res.sum%=mod;
res.squar+=mul(mul(mul(digit,P[len-1]),mul(digit,P[len-1])),mul(1LL,Next.ant));
//res.squar+=(((((digit*P[len-1])%mod)*((digit*P[len-1])%mod))%mod)*next.ant)%mod;
res.squar%=mod;
res.squar+=mul(2LL,mul(Next.sum,mul(digit,P[len-1])));
//res.squar+=(2LL*((next.sum*((digit*P[len-1])%mod))%mod))%mod;
res.squar%=mod;
res.squar+=Next.squar;
res.squar%=mod;
//cout<<"------"<<endl;
//cout<<res.ant<<endl;
//cout<<res.squar<<endl;
//cout<<res.sum<<endl;
//cout<<"-----"<<endl;
}
//cout<<len<<' '<<digit<<' '<<pre<<' '<<pre_<<' '<<res.ant<<' '<<res.sum<<' '<<res.squar<<endl;
if(!up){
dp[len][digit][pre][pre_]=res;
}
return res;
}
ll solve(ll x){
int tot=0;
node ans;
while(x){
num[++tot]=x%10;
x/=10;
}
ans=dfs(tot+1,0,1,0,0);
return ans.squar;
}
int main(){
P[0]=1;
for(int i=1;i<=20;i++){
P[i]=P[i-1]*10LL;
P[i]%=mod;
//cout<<P[i]<<' '<<endl;
}
int t;
for(int i=0;i<20;i++)
for(int j=0;j<10;j++)
for(int k=0;k<8;k++)
for(int p=0;p<8;p++)
dp[i][j][k][p].INIT();
ll n,m;
scanf("%d",&t);
while(t--){
scanf("%I64d%I64d",&n,&m);
printf("%I64d\n",(solve(m)-solve(n-1)+mod)%mod);
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}