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