 /**//*
題意:問[1,n]內有多少個數能被13整除,且包含子串"13"

這題請教了龍教主 Orz

對于這種[1,n]的,比較好的做法就是逐位統計
對于當前位bit[i](i之前的所有位已確定),枚舉[0,bit[i]),然后i之后的位自由變化
對于自由變化的那些情況,可以預處理出來,那些是不需約束的情況
(感覺就是按前綴分類計算,含0個前綴,1個前綴 的所有小于n的數)

dp1[i][j][k]表示當前位為i,數字為j,余數為k,有13的個數
dp2[i][j][k]表示當前位為i,數字為j,余數為k,沒有13的個數
數位統計時注意不要重復計算了
*/
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int dp1[11][11][14],dp2[11][11][14];
int ten[11],bit[11];

void init()
  {
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
ten[0] = 1;
for(int i=1;i<10;i++)
ten[i] = ten[i-1]*10;
for(int j=0;j<10;j++)
dp2[0][j][j] = 1;
for(int i=1;i<10;i++)//len
for(int j=0;j<10;j++)
for(int jj=0;jj<10;jj++)
for(int k=0;k<13;k++)
 {
int kk = (ten[i]*j+k)%13;//
dp1[i][j][kk] += dp1[i-1][jj][k];
if(j==1&&jj==3)dp1[i][j][kk] += dp2[i-1][jj][k];
else dp2[i][j][kk] += dp2[i-1][jj][k];
}
}

bool chk(int x)
  {
char str[20];
sprintf(str,"%d",x);
for(int i=0;str[i+1];i++)
if(str[i]=='1' && str[i+1]=='3')return true;
return false;
}
int main()
  {
init();
int n;
while(~scanf("%d",&n))
 {
int nn = n,tot = 0;
while(nn>0)
 {
bit[tot++] = nn%10;
nn/=10;
}
int ans = 0,last = 0,pre = 0;
bool flag = false;
if(chk(n) && n%13 == 0)ans++;
for(int i = tot-1;i>=0;i--)
 {
for(int j = bit[i]-1;j>=0;j--)
 {
for(int k=0;k<13;k++)
 {
int kk = (pre+k)%13;
if(kk==0)
 {
ans += dp1[i][j][k];
if(flag)ans+=dp2[i][j][k];
if(flag==0&&last==1&&j==3)ans += dp2[i][j][k];//這里需要加flag==0!
break; //若flag=1,這種情況就屬于有前綴13的那種情況了
} //n = 1314
} // 在131*時就已經算了1313的情況了
}
if(last==1 && bit[i] ==3)flag = true;
last = bit[i];
pre += bit[i]*ten[i];
}
printf("%d\n",ans);
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|