數位DP總結
阿新 • • 發佈:2017-10-24
eth while init tmp digits 推斷 logs tdi lcm
杭州交通管理局經常會擴充一些的士車牌照,新近出來一個好消息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。
不吉利的數字為所有含有4或62的號碼。例如:
62315 73418 88914
都屬於不吉利號碼。但是,61152雖然含有6和2,但不是62連號,所以不屬於不吉利數字之列。
你的任務是,對於每次給出的一個牌照區間號,推斷出交管局今次又要實際上給多少輛新的士車上牌照了。
a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.
問一個區間內[l,r]有多少個Beautiful數字
範圍9*10^18
思路一般,但是取模以及映射也是非常玄妙的
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define ll long long //杭州人稱那些傻乎乎粘嗒嗒的人為62(音:laoer)。dp[i][j][k][sta] means the first i nomber,whether it has limit,the val%2520,the lcm of ezch number ll pow[22],dp[22][2][2520][50]; int num[22],flcm[512],Map[2520],Map1[50],tmp[22],tot; int gcd(int a,int b) { if(!b) return a; return gcd(b,a%b); } int lcm(int a,int b) { if(a==0) returnb; if(b==0) return a; return a*b/gcd(a,b); } void init() { pow[0]=1; for(int i=1;i<=18;i++) { pow[i]=pow[i-1]*10%2520; } for(int i=1;i<(1<<9);i++) for(int j=1;j<=9;j++) if(i&(1<<j-1)) flcm[i]=lcm(flcm[i-(1<<j-1)],j); for(int i=1;i<=(1<<9);i++) if(!Map[flcm[i]]) Map1[++tot]=flcm[i],Map[flcm[i]]=tot; } ll solve(ll x) { int len=0; ll ans=0; while(x) tmp[++len]=x%10,x/=10; for(int i=1;i<=len;i++) num[i]=tmp[len-i+1]; memset(dp,0,sizeof(dp)); dp[0][1][0][1]=1; for(int i=0;i<=len;i++) for(int j=0;j<2;j++) for(int k=0;k<2520;k++) for(int l=1;l<=tot;l++) { ll p=dp[i][j][k][l]; int pp=Map1[l]; if(!p) continue; if (i==len) { if (k % pp==0) ans+=p; continue; } if(!j) { for(int q=0;q<=9;q++) { dp[i+1][0][(k+q*pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p; } }else { for(int q=0;q<num[i+1];q++) { dp[i+1][0][(k+q*pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p; } dp[i+1][1][(k+num[i+1]*pow[len-i-1])%2520][Map[lcm(pp,num[i+1])]]+=p; } } return ans; } int main() { init(); int cas; scanf("%d",&cas); while(cas--) { ll a,b; scanf("%lld %lld",&a,&b); printf("%lld\n",solve(b)-solve(a-1)); } }
杭州交通管理局經常會擴充一些的士車牌照,新近出來一個好消息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。
不吉利的數字為所有含有4或62的號碼。例如:
62315 73418 88914
都屬於不吉利號碼。但是,61152雖然含有6和2,但不是62連號,所以不屬於不吉利數字之列。
你的任務是,對於每次給出的一個牌照區間號,推斷出交管局今次又要實際上給多少輛新的士車上牌照了。
Input輸入的都是整數對n、m(0<n≤m<1000000),如果遇到都是0的整數對,則輸入結束。
Output對於每個整數對,輸出一個不含有不吉利數字的統計個數,該數值占一行位置。
Sample Input
1 100 0 0
Sample Output
80
水體不解釋
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int dp[25][2][2],tmp[25],num[25]; int solve(int x) { int len=0,ans=0; while(x) tmp[++len]=x%10,x/=10; for(int i=1;i<=len;i++) num[len-i+1]=tmp[i]; memset(dp,0,sizeof(dp)); dp[0][1][0]=1; for(int i=0;i<=len;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) { int pp=dp[i][j][k]; if(!pp) continue; if(i==len) ans+=pp; if(!j) { if(!k) { for(int q=0;q<=9;q++) if(q!=6&&q!=4) dp[i+1][0][0]+=pp;else if(q!=4)dp[i+1][0][1]+=pp; }else for(int q=0;q<=9;q++) if(q!=6&&q!=2&&q!=4) dp[i+1][0][0]+=pp;else if(q==6) dp[i+1][0][1]+=pp; }else { if(!k) { for(int q=0;q<num[i+1];q++) if(q!=6&&q!=4) dp[i+1][0][0]+=pp;else if(q!=4)dp[i+1][0][1]+=pp; if(num[i+1]!=6&&num[i+1]!=4) dp[i+1][1][0]+=pp;else if(num[i+1]!=4)dp[i+1][1][1]+=pp; }else { for(int q=0;q<num[i+1];q++) if(q!=6&&q!=2&&q!=4) dp[i+1][0][0]+=pp;else if(q==6) dp[i+1][0][1]+=pp; if(num[i+1]!=6&&num[i+1]!=2&&num[i+1]!=4) dp[i+1][1][0]+=pp;else if(num[i+1]==6) dp[i+1][1][1]+=pp; } } } return ans; } int main() { int a,b; while(~scanf("%d %d",&a,&b)&&(a||b)) { printf("%d\n",solve(b)-solve(a-1)); } }
數位DP總結