標籤:手機 ems pre 更新 輸出 表示 stdout 正整數 alc
Description
人們選擇手機號碼時都希望號碼好記、吉利。比如號碼中含有幾位相鄰的相同數字、不含諧音不
吉利的數字等。手機電訊廠商在發行新號碼時也會考慮這些因素,從號段中選取含有某些特徵的號
碼單獨出售。為了便於前期規劃,電訊廠商希望開發一個工具來自動統計號段中滿足特徵的號碼數
量。
工具需要檢測的號碼特徵有兩個:號碼中要出現至少3個相鄰的相同數字,號碼中不能同
時出現8和4。號碼必須同時包含兩個特徵才滿足條件。滿足條件的號碼例如:13000988721、
23333333333、14444101000。而不滿足條件的號碼例如:1015400080、10010012022。
手機號碼一定是11位元,前不含前置的0。工具接收兩個數L和R,自動統計出[L,R]區間
內所有滿足條件的號碼數量。L和R也是11位的手機號碼。
Input
輸入檔案內容只有一行,為空白格分隔的2個正整數L,R。
10^10 < = L < = R < 10^11
Output
輸出檔案內容只有一行,為1個整數,表示滿足條件的手機號數量。
Sample Input
12121284000 12121285550
Sample Output
5
範例解釋
滿足條件的號碼: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550
題解
數位DP,依次確定每一位。設狀態\(f[i][j][0/1][0/1][0/1][0/1][0/1]\)表示確定了前\(i\)位,且第\(i\)位為\(j\),最後兩位是否相同,是否有相鄰三個相同的數,是否有\(4\),是否有\(8\),當前確定的位是否達到上界的滿足條件的數的個數。
然後寫一個八重迴圈,枚舉這七個值以及\(i+1\)位填的數,更新新的狀態。
題解
#include<bits/stdc++.h>#define LL long long#define up(x,y,z) for(int x=y;x<=z;x++)using namespace std;LL f[15][12][2][2][2][2][2],l,r;//當前處理了i位 第i位是j 最後兩位是否相同 //是否存在連續三個相同的數 是否有4 是否有8 首碼是否達到上限 int p[15],cnt,a,b,c,d,e;LL Calc(LL x){//開區間 memset(f,0,sizeof(f)); LL t=x,ans=0;cnt=0; while(t){p[++cnt]=t%10;t/=10;} reverse(p+1,p+1+cnt); f[0][10][0][0][0][0][1]=1; up(i,0,cnt-1) up(j,0,10) up(k1,0,1) up(k2,0,1) up(k3,0,1) up(k4,0,1) up(k5,0,1) if(f[i][j][k1][k2][k3][k4][k5]) up(k,0,9){ if(k5&&k>p[i+1])continue; a=(k==j); b=k2? k2:((a+k1)==2); c=k3? k3:k==4; d=k4? k4:k==8; if(c&d)continue; e=(k5&&k==p[i+1]); f[i+1][k][a][b][c][d][e]+=f[i][j][k1][k2][k3][k4][k5]; } up(i,0,9) up(k1,0,1) up(k3,0,1) up(k4,0,1){ if(k3&k4)continue; ans+=f[cnt][i][k1][1][k3][k4][0]; } return ans;}int main(){ #ifndef ONLINE_JUDGE freopen("bzoj4521.in","r",stdin); freopen("bzoj4521.out","w",stdout); #endif scanf("%lld%lld",&l,&r); printf("%lld",Calc(r+1)-Calc(l)); return 0; }
bzoj4521: [Cqoi2016]手機號碼