[bzoj1223] [HNOI2002]Kathy函数

  首先由题解可得TAT,f(i)=i当且仅当i在二进制下为回文串。

  那么问题就变成了1~n中有多少个二进制下的回文串。

  把m转成2进制后就是正常的统计了= =。

  f[i]表示二进制下,有多少个i位的回文串(包括前导0)。f[1]=f[2]=2,f[i]=f[i-2]*2.....也就是f[i]=2^((i+1)/2)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ri register int
 6 using namespace std;
 7 const int modd=1000000000;
 8 char s[103];
 9 int two[340][20];
10 int a[20],l[340],len,len2,mp[340],ten[10];
11 int i,j,k,n,m;
12 int ans[20],ansl;
13  
14 inline bool notsmall(int x){
15     if(l[x]!=len)return l[x]>len;
16     for(ri i=len;i;i--)if(two[x][i]!=a[i])return two[x][i]>a[i];
17     return 1;
18 }
19 inline bool notbig(int x){
20     if(l[x]!=len)return l[x]<len;
21     for(ri i=len;i;i--)if(two[x][i]!=a[i])return two[x][i]<a[i];
22     return 1;
23 }
24 inline void add(int x){
25     l[x]=l[x-1];int y=x-1;
26     for(ri i=1;i<=l[x];i++){
27         two[x][i]+=two[y][i]<<1;
28         if(two[x][i]>=modd)two[x][i]-=modd,two[x][i+1]++;
29     }
30     if(two[x][l[x]+1])l[x]++;
31 }
32 inline void addtoans(int x){
33     for(ri i=1;i<=l[x];i++){
34         ans[i]+=two[x][i];
35         if(ans[i]>=modd)ans[i+1]++,ans[i]-=modd;
36     }
37     while(ans[ansl+1])ansl++;
38 }
39 inline void dec(int x){
40     for(ri i=1;i<=l[x];i++){
41         a[i]-=two[x][i];
42         if(a[i]<0)a[i]+=modd,a[i+1]--;
43     }
44     while(!a[len]&&len>1)len--;
45 }
46 inline void run(){
47     ri i,j,k,len;
48     two[1][l[1]=1]=1;
49     for(i=1;!notsmall(i);)i++,add(i);
50     for(;i;i--)
51         if(notbig(i))dec(i),mp[i]=1,len2=max(len2,i);
52 //    for(i=len2;i;i--)printf(" %d",mp[i]);puts("");
53     for(i=1;i<len2;i++)addtoans((i+1)>>1);
54     int flag=3;
55     for(i=len2>>1;i;i--)swap(mp[i],mp[len2-i+1]);
56     for(i=2;i<=len2&&flag;i++){
57         if(mp[i]){
58             if(i<=(len2>>1))addtoans((len2-(i<<1)+3)>>1);
59             else{
60                 if(mp[len2-i+1]==0||len2-i+1==i)addtoans(1);
61             }
62         }
63         if(i>(len2>>1))flag&=(mp[len2-i+1]==mp[i]);
64     }
65     if(flag==1||len2==1)addtoans(1);
66 }
67 int main(){
68     scanf("%s",s);j=strlen(s);
69     for(i=ten[0]=1;i<=9;i++)ten[i]=ten[i-1]*10;
70     for(i=j-1;i>=0;i--){
71         if(!k)len++;
72         a[len]+=(s[i]-'0')*ten[k];
73         k++;if(k>8)k=0;
74     }
75     run();
76     for(printf("%d",ans[ansl]),i=ansl-1;i>0;i--){
77         for(j=10;j<modd;j*=10)if(ans[i]<j)putchar('0');
78         printf("%d",ans[i]);
79     }puts("");
80     return 0;
81 }
View Code

代码又丑又慢>_<

转载于:https://www.cnblogs.com/czllgzmzl/p/5253731.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值