[hdu5632][BC#73 1002]Rikka with Array
2016-02-27 20:15
417 查看
点开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+人过... 实在没法再卡常了
View Code
一开始被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+人过... 实在没法再卡常了
#include<cstdio> #include<iostream> #include<cstring> #define ll long long #define MOD(x) x-=x>=modd?modd:0 #define modd 998244353 using namespace std; int f[1000][1000],g[1003],nowsm[1003],pre[1003]; int two[12]; int i,j,k,n,m,len,len1; char s1[333],s[1003]; inline void turn(){ len=0; register int i,l=1; while(l<=len1&&s1[l]){ s[++len]=s1[len1]&1; for(i=l;i<=len1;i++) s1[i+1]+=(s1[i]&1)?10:0,s1[i]>>=1; if(!s1[l])l++; } } inline int get(){ register int i,pr=0,sm;int ans=g[len-1]; memset(pre,0,sizeof(pre)); memcpy(pre,f[len-1],len<<2); pr=1; for(i=len-1;i;pr+=s[i--]) if(s[i]){ for(ans+=g[i-1],MOD(ans),sm=0,j=len;j>=pr;j--) sm+=pre[j],MOD(sm); for(j=0,k=pr;j<=i;j++,k++) sm-=pre[k],sm+=sm<0?modd:0, ans=(ans+(ll)f[i-1][j]*sm)%modd, pre[k]+=f[i-1][j],MOD(pre[k]); } for(i=len;i>pr;i--)ans+=pre[i],MOD(ans); return ans; } int main(){ register int i,j; for(i=0;i<=999;i++)f[i][0]=1;f[1][1]=1; for(i=2,g[1]=0;i<=999;i++){ g[i]=g[i-1]<<1,MOD(g[i]); ll sm=0; for(j=1;j<=i;j++) sm+=f[i-1][j],f[i][j]=f[i-1][j]+f[i-1][j-1],MOD(f[i][j]); for(j=0;j<i;j++) sm-=f[i-1][j+1], g[i]=(g[i]+sm%modd*f[i-1][j])%modd; } int T;scanf("%d",&T); while(T--){ scanf("%s",s1);len1=strlen(s1);for(i=len1;i;i--)s1[i]=s1[i-1]-48; turn(), printf("%d\n",get()); } return 0; }
View Code
相关文章推荐
- C# 枚举、字符串、值的相互转换
- C#学习语录
- C#虚基类继承与接口的区别
- C#_在VS2010下进行单元测试
- C# String与string的区别
- C# 中的委托和事件
- C# 索引器的使用
- C#套接字使用
- C#获取 URL参数
- C#判断
- C#多线程动态读取word文档代码
- 【C#】报表制作<机房重构>
- C#进行AutoCAD二次开发实例之倒角功能实现原理介绍
- C# 委托的简单使用
- Atitit .c#的未来新特性计划草案
- Atitit .c#的未来新特性计划草案
- Atitit .c#的未来新特性计划草案
- C#中接口和抽象类的区别
- 委托进阶
- C#Winform中DataGridView控件下的右键菜单事件获取行值方法