http://ac.jobdu.com/problem.php?pid=1491
举个例子来阐明解题的基本思路。例如,n=4321,我们对其各个数位进行分解,4321=4000+300+20+1,然后从低位到高位一次进行分析。个位1,只能含一个1,而十位20又可分为1~10和11~20,个位数字有两次循环,而每次循环会出现一个1和一个2,十位10~19又含有十个1,20含有一个2。百位300,低两位数字有3次循环,同时,100~199和200~299又各含有一百个1和一百个2。
故我们得到这样的结论,每增加一个高位,应该这样计算新增的个数:高位的数字(即低位循环次数)乘以一个低位循环中的1 2数,高位数字为1或2时新增的1 2数,这个要分类讨论,高位数在【0,1】【1,2】【2,9】三个区间新增的1 2数不同,要具体分析。高位数小于1时,不会在该位出现1 2,高位数在等于1(2)时,低位数最大值+1即为新增的高位1(2),高位数大于1(2)时,该位的位权值即为新增的高位1(2)。代码如下
#include <stdio.h>
#include <string.h>
#define MOD 20123
int ten[110],len;
char s[10000];
int cal(int x, int i, int temp)
{
int ret=0;
if (s[i]-'0'==x)
{
for (int j=len-1;j>i;--j)
ret+=(s[j]-'0')*ten[len-1-j]%MOD;
ret=(ret+1)%MOD;
}
else if (s[i]-'0'>x)
ret=ten[len-1-i];
return ret;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
ten[0]=1;
for (int i=1;i<110;++i)
ten[i]=ten[i-1]*10%MOD;
while (scanf("%s",s)!=EOF)
{
len=strlen(s);
int ans=0,temp=0;
for (int i=len-1;i>=0;--i)
{
ans=(ans+(s[i]-'0')*temp)%MOD; //temp用来求每次低位循环含有的1 2数
ans=(ans+cal(1,i,temp))%MOD;
ans=(ans+cal(2,i,temp))%MOD;
temp=(10*temp+2*ten[len-1-i])%MOD;
}
printf("%d\n",ans);
}
return 0;
}