DP中平方的转换

Posted milky-w

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP中平方的转换相关的知识,希望对你有一定的参考价值。

NOI 2009 管道取珠

……设第 i 种输出序列的产生方式(即不同的操作方式数目)有 ai 个,Σai=C(n+m,n)。求 Σ(ai)²。

直接求 ai 是不好做的,由于平方的存在,可以看做两个人同时玩这个游戏,得到的序列完全相同的个数。

 


 

2017/11/01 胡策 T3

一年一度的运动会开始了。有 N 个选手参赛,第 i 个选手有一个能力值 Ai,比赛一共进行了 2^M 天。
在第 j 天 (0?j?2^M−1) 的比赛中,第 i 个选手的得分为 A[i] xor j,然后从大到小排名,排名为 x (x 从 0 开始) 的同学会获得 x^2 的积分。
你需要求出每个同学最后总的积分和 q[i] 模 1e9+7 的结果 p[i]。为了避免输出文件过大,你只要输出 p[i] 的异或和即可。

对于 10% 的数据,M <= 5;
对于 30% 的数据,N <= 100;
对于 50% 的数据,N <= 1000;
对于 100% 的数据,N <= 200000,M <= 30,A[i] < 2^M。

  

  这个题的“得分”和“积分”好坑。。

  考虑 x^2 的意义,相当于两个人 (可以相同) 同时排在选手 i 前面的组合数。
  考虑异或的性质,两个数的大小取决于二进制中不相同的最高位,而这里异或的是一段连续的数 0~2^(M-1),所以 A 排在 B 前面的天数为 2^M / 2 即 2^(M-1) 天,A 和 C 同时排在 B 前面的天数就是 2^(M-2) 天,因为要使两个二进制数位同时等于 1。对于每个人,求出 f[i] 表示能力值与他不相同的最高位为第 i 位的人数,枚举 i 和 j,累加 f[i] * f[j] * 2^(M-2)。

  求 f[i] 的过程可以用 trie。总的复杂度大概是 O(NM^2)。

 

技术分享图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<map>
 6 #define ll long long
 7 
 8 using namespace std;
 9 
10 const int N=200003;
11 const int mod=1000000007;
12 int n,m,A,ch[N*30][2],tot=0,sz[N*30];
13 ll ans=0;
14 
15 void insert(int A)
16 {
17     int now=0;
18     for (int i=m-1;i>=0;i--)
19     {
20         int x=(A>>i)&1;
21         if (!ch[now][x]) ch[now][x]=++tot;
22         now=ch[now][x];
23         sz[now]++;                 //每个节点上的子串个数 
24     }
25 }
26 
27 void dfs(int x,ll sum,ll num)
28 {
29     ll tmp,size;
30 
31     size=sz[ch[x][1]],tmp=0;
32     tmp=size*size%mod*(1<<m-1)%mod;
33     tmp=(tmp+size*num%mod*(1<<m-1)%mod)%mod;
34     if (ch[x][0]) dfs(ch[x][0],(sum+tmp)%mod,num+size);
35 
36     size=sz[ch[x][0]],tmp=0;
37     tmp=size*size%mod*(1<<m-1)%mod;
38     tmp=(tmp+size*num%mod*(1<<m-1)%mod)%mod;
39     if (ch[x][1]) dfs(ch[x][1],(sum+tmp)%mod,num+size);
40 
41     if (!ch[x][0]&&!ch[x][1]) ans^=sum;
42 }
43 
44 map<int,bool> vis;
45 
46 int main()
47 {
48     freopen("race.in","r",stdin);  
49     freopen("race.out","w",stdout);
50     scanf("%d%d",&n,&m);
51     for (int i=1;i<=n;i++) 
52     {
53         scanf("%d",&A);
54         insert(A);
55         if (vis.count(A)) return 0;
56         vis[A]=1;
57     }
58     dfs(0,0,0);
59     printf("%lld",ans);
60     return 0; 
61 }
View Code

 

以上是关于DP中平方的转换的主要内容,如果未能解决你的问题,请参考以下文章

[Leetcode]279.完全平方数

[JavaScript 刷题] DP - 组成整数的最小平方数数量, leetcode 279

leetcode 279. Perfect Squares 完全平方数(中等)

HDU 3507 单调队列 斜率优化

添加两个窗格的平板电脑布局会导致在移动设备中找不到视图(小于w600dp)

哈斯克尔。我很困惑这个代码片段是如何工作的