点开BC发现今晚没比赛。。然后似乎上一场有数位DP?...(幸好我没去
一开始被BCDcode那题的思路带歪了。。后来发现得把n转成二进制才能搞TAT
题目大概是要求一种类似逆序对的鬼东西:
有一个长度为 n 的数组 A(下标为 1 到 n),A_i 为 i 的二进制表示中的1的个数,例如 A[1]=1, A[3]=2, A[10]=2。
现在勇太想知道数组 A 中满足 A[ i ]>A[ j ] 的数对 ( i , j )(1 ≤ i < j ≤ n) 的个数。
f[i][j]表示二进制下,i位的数有j个1的方案数(其实也就是组合数了
再预处理出g[i]表示二进制下,i位的数中,满足题意的数对的个数。
统计的时候用pre[i]表示 之前的数中,1的个数为i的数的个数。
其实有点像逆序对的那题(hdu5225)
统计的时候,一开始脑残写了发树状数组,然后复杂度比正解多一个log神奇的200+ms过了(中途还在纠结树状数组怎么写233)
吐槽了一下数据强度,然后发现自己傻逼了...弄个变量记录就行了TAT。。所以总的时间复杂度是O(10 * log²n)(logn是<1000的)
然后就46ms跑过去啦。。并列#1。。。(因为是新题...目前这题才30+人过... 实在没法再卡常了
1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #define ll long long
5 #define MOD(x) x-=x>=modd?modd:0
6 #define modd 998244353
7 using namespace std;
8
9 int f[1000][1000],g[1003],nowsm[1003],pre[1003];
10 int two[12];
11 int i,j,k,n,m,len,len1;
12 char s1[333],s[1003];
13
14 inline void turn(){
15 len=0;
16 register int i,l=1;
17 while(l<=len1&&s1[l]){
18 s[++len]=s1[len1]&1;
19 for(i=l;i<=len1;i++)
20 s1[i+1]+=(s1[i]&1)?10:0,s1[i]>>=1;
21 if(!s1[l])l++;
22 }
23 }
24
25 inline int get(){
26 register int i,pr=0,sm;int ans=g[len-1];
27 memset(pre,0,sizeof(pre));
28 memcpy(pre,f[len-1],len<<2);
29 pr=1;
30 for(i=len-1;i;pr+=s[i--])
31 if(s[i]){
32 for(ans+=g[i-1],MOD(ans),sm=0,j=len;j>=pr;j--)
33 sm+=pre[j],MOD(sm);
34 for(j=0,k=pr;j<=i;j++,k++)
35 sm-=pre[k],sm+=sm<0?modd:0,
36 ans=(ans+(ll)f[i-1][j]*sm)%modd,
37 pre[k]+=f[i-1][j],MOD(pre[k]);
38 }
39 for(i=len;i>pr;i--)ans+=pre[i],MOD(ans);
40 return ans;
41 }
42 int main(){
43 register int i,j;
44 for(i=0;i<=999;i++)f[i][0]=1;f[1][1]=1;
45 for(i=2,g[1]=0;i<=999;i++){
46 g[i]=g[i-1]<<1,MOD(g[i]);
47 ll sm=0;
48 for(j=1;j<=i;j++)
49 sm+=f[i-1][j],f[i][j]=f[i-1][j]+f[i-1][j-1],MOD(f[i][j]);
50 for(j=0;j<i;j++)
51 sm-=f[i-1][j+1],
52 g[i]=(g[i]+sm%modd*f[i-1][j])%modd;
53 }
54
55 int T;scanf("%d",&T);
56 while(T--){
57 scanf("%s",s1);len1=strlen(s1);for(i=len1;i;i--)s1[i]=s1[i-1]-48;
58 turn(),
59 printf("%d
",get());
60 }
61 return 0;
62 }