 /**//*
题意:问[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
搜索
最新评论

|
|