zoukankan      html  css  js  c++  java
  • HDU 6304 Chiaki Sequence Revisited

    题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=6304
    多校contest1
     
    Problem Description

    Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as follows:

    an={1anan1+an1an2n=1,2n3


    Chiaki would like to know the sum of the first n terms of the sequence, i.e. i=1nai. As this number may be very large, Chiaki is only interested in its remainder modulo (109+7).

    Input
    There are multiple test cases. The first line of input contains an integer T (1T105), indicating the number of test cases. For each test case:
    The first line contains an integer n (1n1018).
     
    Output

    For each test case, output an integer denoting the answer.

     题目大意是求一个 奇怪序列的 前 n 项 和,n最坏情况达 1e18。
    开始打了个表,发现在序列是从1开始的连续整数(每个整数出现的次数不同),除了数字 1是出现两次,其他数字 如x 都是出现 lowbit(x)后缀0的个数+1 次。 如2(10) 出现2次 ,3(11) 出现1次,4(100) 出现3次,5(101)出现1次,6(110) 出现2次...
    可以发现这是一个十分有特点的(类似2进制,有部分对称性)的序列
    接下来我们可以发现如果把1当做出现1次,出现在 2^n 上,如果占满 ,次数总和刚好是 2^(n+1) -1 次,那么多出来的数似乎又没有规律了,这时我们可以利用局部对称与这个和二进制相似的特点,找到 第 n 个数 是数字多少(落在图中的位置),
    有两种方法:
    第一种 可以知道N(自减一后)对应的准确数字,但不知N落在的数字差几次被填满,不便计算。
     1 void init(){
     2     P[0]=1;P[1]=2;
     3     nP[0]=0;nP[1]=1;
     4     for(int i=2;i<=62;++i){
     5         P[i]=2*P[i-1];
     6         nP[i]=P[i]-1;
     7     }
     8 }
     9 
    10 ll getbound(ll N){
    11     ll bound=0;
    12     for(int i=62;i>=1;--i){
    13         while(N>=nP[i]){
    14             N-=nP[i];
    15             bound+=P[i-1];
    16         }
    17     }
    18     return bound;
    19 }

    第二种 完全参照二进制,可知N(自减一后)所落在的数字最近的次数填满数字,后来计算时很方便。

     1 void init(){
     2     P[0]=1;P[1]=2;
     3     nP[0]=0;nP[1]=1;
     4     for(int i=2;i<=62;++i){
     5         P[i]=2*P[i-1];
     6         nP[i]=P[i]-1;
     7     }
     8 }
     9 
    10 ll getbound(ll& N){
    11     ll bound=0;
    12     for(int i=62;i>=1;--i){
    13         if(N>=nP[i]){
    14             N-=nP[i];
    15             bound+=P[i-1];
    16         }
    17     }
    18     return bound;
    19 }

    计算时可以可利用每个数字出现的次数,是1(2^0)的倍数的出现过一次,是2(2^1)的倍数的额外出现过一次,是4(2^2)的倍数的又额外出现一次,,,(这也恰恰是后缀0的意义)

    在这里贴两份按照上述两种方法写的代码。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef long long ll;
     5 
     6 const ll MOD=1e9+7;
     7 ll P[66];
     8 ll nP[66];
     9 ll a[101];
    10 ll arr[101];
    11 
    12 ll lowbit(ll x){
    13     ll low=x&(-x);
    14     ll cnt=0;
    15     while(low>>=1){
    16         cnt++;
    17     }
    18     return cnt;
    19 }
    20 
    21 void init(){
    22     P[0]=1;P[1]=2;
    23     nP[0]=0;nP[1]=1;
    24     for(int i=2;i<=62;++i){
    25         P[i]=2*P[i-1];
    26         nP[i]=P[i]-1;
    27     }
    28     
    29     //a[1]=1;a[2]=1;
    30     //arr[1]=1;arr[2]=2;
    31     //for(int i=3;i<101;i++){
    32     //    a[i]=a[i-a[i-1]]+a[i-1-a[i-2]];
    33     //    arr[i]=arr[i-1]+a[i];
    34     //}
    35     
    36     //for(int i=1;i<101;++i) printf("%lld
    ",arr[i]);
    37     
    38 }
    39 
    40 ll inv(ll a,ll m){
    41     if(a==1) return 1;
    42     return inv(m%a,m)*(m-m/a)%m;
    43 }
    44 
    45 ll getbound(ll N){
    46     ll bound=0;
    47     for(int i=62;i>=1;--i){
    48         while(N>=nP[i]){
    49             N-=nP[i];
    50             bound+=P[i-1];
    51         }
    52     }
    53     return bound;
    54 }
    55 
    56 int main(){
    57     //freopen("data.in","r",stdin);
    58     //freopen("data1.out","w",stdout);
    59     init();
    60     int T;
    61     scanf("%d",&T);
    62     while(T--){
    63         ll N;
    64         scanf("%lld",&N);
    65         if(N==1) puts("1");
    66         else{
    67             ll ans=0;
    68             N-=1ll;
    69             ll bound=0;
    70             bound=getbound(N);
    71             //printf("bound = %lld
    ",bound);
    72             ll cnt=lowbit(bound)+1ll;
    73             ll tot=N;
    74             for(ll i=1;i<=cnt;++i){
    75                 if(bound==getbound(N+i)) tot++;
    76                 else break;
    77             }
    78             ll _m2=inv(2,MOD);
    79             //printf("%lld
    ",_m2);
    80             for(int i=0;i<=62;++i){
    81                 if(P[i]<=bound){
    82                     ll M=bound/P[i];
    83                     ans=(ans+(P[i]%MOD)*(M%MOD)%MOD*((M+1ll)%MOD)%MOD*_m2%MOD)%MOD;
    84                 }
    85                 else break;
    86             }
    87             //printf("1:%lld
    ",(ans+1)%MOD);
    88             ans=(ans-(bound)*(tot-N)%MOD+MOD)%MOD;
    89             printf("%lld
    ",(ans+1ll)%MOD);
    90             //printf("%I64d %I64d
    ",(ans+1ll)%MOD,arr[N+1]);
    91             //最后加一 
    92         }
    93     }
    94     return 0;
    95 }
    View Code
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef long long ll;
     5 
     6 const ll MOD=1e9+7;
     7 ll P[66];
     8 ll nP[66];
     9 ll a[101];
    10 ll arr[101];
    11 
    12 ll lowbit(ll x){
    13     ll low=x&(-x);
    14     ll cnt=0;
    15     while(low>>=1){
    16         cnt++;
    17     }
    18     return cnt;
    19 }
    20 
    21 void init(){
    22     P[0]=1;P[1]=2;
    23     nP[0]=0;nP[1]=1;
    24     for(int i=2;i<=62;++i){
    25         P[i]=2*P[i-1];
    26         nP[i]=P[i]-1;
    27     }
    28     
    29     //a[1]=1;a[2]=1;
    30     //arr[1]=1;arr[2]=2;
    31     //for(int i=3;i<101;i++){
    32     //    a[i]=a[i-a[i-1]]+a[i-1-a[i-2]];
    33     //    arr[i]=arr[i-1]+a[i];
    34     //}
    35     
    36     //for(int i=1;i<101;++i) printf("%lld
    ",arr[i]);
    37     
    38 }
    39 
    40 ll inv(ll a,ll m){
    41     if(a==1) return 1;
    42     return inv(m%a,m)*(m-m/a)%m;
    43 }
    44 
    45 ll getbound(ll& N){
    46     ll bound=0;
    47     for(int i=62;i>=1;--i){
    48         if(N>=nP[i]){
    49             N-=nP[i];
    50             bound+=P[i-1];
    51         }
    52     }
    53     return bound;
    54 }
    55 
    56 int main(){
    57     //freopen("data.in","r",stdin);
    58     //freopen("data1.out","w",stdout);
    59     init();
    60     int T;
    61     scanf("%d",&T);
    62     while(T--){
    63         ll N;
    64         scanf("%lld",&N);
    65         if(N==1) puts("1");
    66         else{
    67             ll ans=0;
    68             N-=1ll;
    69             ll bound=0;
    70             bound=getbound(N);
    71             //printf("bound = %lld
    ",bound);
    72             //ll cnt=lowbit(bound)+1ll;
    73             //ll tot=N;
    74             //for(ll i=1;i<=cnt;++i){
    75             //    if(bound==getbound(N+i)) tot++;
    76             //    else break;
    77             //}
    78             ll _m2=inv(2,MOD);
    79             for(int i=0;i<=62;++i){
    80                 if(P[i]<=bound){
    81                     ll M=bound/P[i];
    82                     ans=(ans+(P[i]%MOD)*(M%MOD)%MOD*((M+1ll)%MOD)%MOD*_m2%MOD)%MOD;
    83                     
    84                 }
    85                 else break;
    86             }
    87             //printf("1:%lld
    ",(ans+1)%MOD);
    88             ans=(ans+(bound+1)*N%MOD)%MOD;
    89             printf("%lld
    ",(ans+1ll)%MOD);
    90             //printf("%I64d %I64d
    ",(ans+1ll)%MOD,arr[N+1]);
    91             //最后加一 
    92         }
    93     }
    94     return 0;
    95 }
    View Code

    然后,比赛时WA了两发,其实规律找到了,但错在了计算,算总和时,第一个错误处是没用逆元,第二个错误处是P[i]在N为1e18时奇大,应该先mod在相乘。

    血的教训。

    Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as follows:
    an={1anan1+an1an2n=1,2n3

    Chiaki would like to know the sum of the first n terms of the sequence, i.e. i=1nai. As this number may be very large, Chiaki is only interested in its remainder modulo (109+7).
  • 相关阅读:
    vue day6 分页显示
    vue day5 分页控件
    vue day4 table
    c# excel xlsx 保存
    diff算法
    Web Workers
    多线程
    Http请求优化
    高效编写代码
    渲染引擎
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/9363002.html
Copyright © 2011-2022 走看看