zoukankan      html  css  js  c++  java
  • 【hdu 5632】Rikka with Array

    Description

    As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

    Yuta has an array A of length n,and the ith element of A is equal to the sum of all digits of i in binary representation. For example,A[1]=1,A[3]=2,A[10]=2.

    Now, Yuta wants to know the number of the pairs (i,j)(1≤i<j≤n) which satisfy A[i]>A[j].

    It is too difficult for Rikka. Can you help her?

    Input

    The first line contains a number T(T≤10)——The number of the testcases. For each testcase, the first line contains a number n(n≤10300).

    Output

    For each testcase, print a single number. The answer may be very large, so you only need to print the answer modulo 998244353.

    Sample Input

    1 10

    Sample Output

    7

    题意:给定一个数$n(nleq 10^{300})$,问有多少个数对$(i , j)$,满足$1leq i<j leq n$$f[i]>f[j]$$f[x]$$x$二进制表示下$1$的个数。

    分析:(在打模拟赛时写到的题目……好像写了一种跟所有人都不一样的写法)

    首先考虑一个数$x$,我们需要统计满足$1leq i<x$$f[i]>f[x]$$i$的个数。考虑数位dp,将$x$转为二进制形式,从低位往高位推。假设当前在第$i$位,从第$1$位到第$i$位共有$k$$1$:若当前位为$0$,则直接跳过进行下一位的统计;否则钦定当前要统计进答案的数字的比第$i$位高的位置与$x$相同,且第$i$位为$0$,则此时最低的第$i-1$位至少要有$k+1$$1$,可任意选取,即需要统计进答案里的方案数为$sum _{j=k+1}^{i-1} inom{i-1}{j}$ ,令$s(i,j)=sum _{d=0}^{j}inom{i}{d}$,则公式简化为$s(i-1,i-1)-s(i-1,k)$

    现在我们需要统计答案,且因为$n$很大,无法直接枚举。考虑将$n$转成二进制形式,共有$cnt$位,$a_{i}$$n$在二进制下第$i$位上的数字。统计每一个$s(i-1,i-1)-s(i-1,k)$被统计进答案的贡献。若$s(i-1,i-1)-s(i-1,k)$会在数字$x$时被统计进答案里,$x$需要满足以下几个条件:1.$1leq xleq n$,2. $x$的第$i$位为$1$,3.$x$的前$i$位恰好有$k$$1$。答案转化为统计满足条件的$x$的个数。

    我们递推一个数组$f$$f(i,j)$表示数值小于等于$n$最低的$i$位,且二进制下恰好含有$j$$1$的数字的方案数。可得:

    $$f(i,j)=egin{cases}f(i-1,j)~~~~~~~~~~~~~~~~~~~~~~~(a_{i}=0)\f(i-1,j-1)+inom{i-1}{j}~~~(a_{i}=1)end{cases}$$

    特殊的,$f(i,0)=1(0leq ileq cnt)$然后就可以数位dp出对于每一个$(i-1,k)$的组合,所有符合条件的数$x$了。

    枚举当前在第$i$位,前$i-1$位总共有$k$$1$,我们令$num=sum _{d=i+1}^{cnt} 2^{d-(i+1)}cdot a_{d}$,即大于第$i$位的部分的$0$$num-1$的方案,则$s(i-1,i-1)-s(i-1,k+1)$的系数$t$计算方式如下:

    $$t=egin{cases}numcdot inom{i-1}{k}~~~~~~~~~~~~~~~~~~~~~~~~~(a_{i}=0)\numcdot inom{i-1}{k}+f(i-1,k)~~~(a_{i}=1)end{cases}$$

    然后就可以得到最终的答案了。

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e3+5;
     7 const int mod=998244353;
     8 int T,n,cnt,ans,tmp,num,now,t;
     9 int x[N],a[N],C[N][N],s[N][N],f[N][N];
    10 char ch[N];
    11 int read()
    12 {
    13     int x=0,f=1;char c=getchar();
    14     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    15     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    16     return x*f;
    17 }
    18 void Mod(int& a,int b){a+=b;if(a>=mod)a-=mod;}
    19 int main()
    20 {
    21     for(int i=0;i<=1000;i++)C[i][0]=1;
    22     for(int i=1;i<=1000;i++)
    23         for(int j=1;j<=i;j++)
    24             C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    25     for(int i=0;i<=1000;i++)
    26         for(int j=0;j<=1000;j++)
    27             if(j)s[i][j]=(s[i][j-1]+C[i][j])%mod;
    28             else s[i][j]=C[i][j];
    29     T=read();
    30     while(T--)
    31     {
    32         cnt=ans=0;
    33         scanf("%s",ch+1);
    34         n=strlen(ch+1);
    35         for(int i=1;i<=n;i++)x[n-i+1]=ch[i]-'0';
    36         if(n==1&&(x[1]==0||x[1]==1)){printf("0
    ");continue;}
    37         while(n)
    38         {
    39             if(x[1]&1)a[++cnt]=1,x[1]--;
    40             else a[++cnt]=0;
    41             for(int i=n;i>=1;i--)
    42                 if(x[i]&1)x[i]/=2,x[i-1]+=10;
    43                 else x[i]/=2;
    44             while(n&&x[n]==0)n--;
    45         }
    46         memset(f,0,sizeof(f));
    47         for(int i=0;i<=cnt;i++)f[i][0]=1;
    48         for(int j=1;j<=cnt;j++)
    49             for(int i=j;i<=cnt;i++)
    50                 if(!a[i])Mod(f[i][j],f[i-1][j]);
    51                 else
    52                 {
    53                     Mod(f[i][j],f[i-1][j-1]);
    54                     Mod(f[i][j],C[i-1][j]);
    55                 }
    56         for(int i=1;i<=cnt;i++)
    57         {
    58             num=0;
    59             for(int j=cnt;j>i;j--)num=(num*2+a[j])%mod;
    60             for(int j=0;j<i;j++)
    61             {
    62                 t=1ll*num*C[i-1][j]%mod;
    63                 Mod(ans,1ll*(s[i-1][i-1]-s[i-1][j+1]+mod)%mod*t%mod);
    64                 if(!a[i])continue;
    65                 Mod(ans,1ll*(s[i-1][i-1]-s[i-1][j+1]+mod)%mod*f[i-1][j]%mod);
    66             }
    67         }
    68         printf("%d
    ",ans);
    69     }
    70     return 0;
    71 }
    View Code
  • 相关阅读:
    jsp数据交互二
    jsp数据交互(一)
    JQuery操作DOM
    事件和动画
    Jquery选择器
    Optional容器(jdk1.8)
    java常见集合笔记
    字符串内存占用图解
    单例设计模式
    代码块
  • 原文地址:https://www.cnblogs.com/zsnuo/p/8893768.html
Copyright © 2011-2022 走看看