HDU 6057 Kanade's convolution

题目链接:HDU-6057

题意:

思路:先按照官方题解推导出下面的式子:

现在唯一的问题就是怎么解决[bit(x)-bit(y)=bit(k)]的问题。

我们定义\( F(A,k)_{i}=\left[ bit\left( i\right) =k\right] * A_{i} \),相当于把A、B、C分别按照bit划分成m+1个序列。

有如下公式:

同时我们发现\( C_k=F(C,bit(k)))_k \)。

然后我们就可以搞出来啦!

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 using namespace std;
  6 typedef long long LL;
  7
  8 const LL MAXN=600010;
  9 const LL MOD=998244353;
 10 LL A[32][MAXN],B[32][MAXN],C[32][MAXN];
 11 LL two[32];
 12 LL bit(LL x)
 13 {
 14     LL ret=0;
 15     while(x>0)
 16     {
 17         if(x&1) ret++;
 18         x>>=1;
 19     }
 20     return ret;
 21 }
 22 // 快速幂
 23 // 求x^n%mod
 24 // Verified!
 25 LL powMod(LL x,LL n,LL mod)
 26 {
 27     LL res=1;
 28     while(n>0)
 29     {
 30         if(n&1) res=res*x % mod;
 31         x=x*x % mod;
 32         n>>=1;
 33     }
 34     return res;
 35 }
 36 LL inv(LL a,LL m)
 37 {
 38     return powMod(a,m-2,m);
 39     // return powMod(a,eularPhi(m)-1,m);
 40 }
 41 LL inv2;
 42 void FWT_Xor(LL *A, LL len) {
 43   if (len == 1) return;
 44   LL len2 = len >> 1;
 45   FWT_Xor(A, len2);
 46   FWT_Xor(A + len2, len2);
 47   for (LL i = 0; i < len2; ++i) {
 48     LL x = A[i], y = A[i + len2];
 49     A[i] = (x + y) % MOD;
 50     A[i + len2] = ((((x - y) % MOD) + MOD) % MOD);
 51   }
 52 }
 53 void IFWT_Xor(LL *A, LL len) {
 54   if (len == 1) return;
 55   LL len2 = len >> 1;
 56   for (LL i = 0; i < len2; ++i) {
 57     LL x = A[i], y = A[i + len2];
 58     A[i] = ((x + y) % MOD) * inv2 % MOD;
 59     A[i + len2] = ((((x - y) % MOD) + MOD) % MOD) * inv2 % MOD;
 60   }
 61   IFWT_Xor(A, len2);
 62   IFWT_Xor(A + len2, len2);
 63 }
 64 int main()
 65 {
 66 #ifdef LOCAL
 67     freopen("in.txt","r",stdin);
 68 #endif
 69     inv2=inv(2,MOD);
 70     memset(A,0,sizeof(A));
 71     memset(B,0,sizeof(B));
 72     memset(C,0,sizeof(C));
 73     two[0]=1;
 74     for(LL i=1;i<32;i++) two[i]=two[i-1]*2%MOD;
 75
 76     LL m;
 77     scanf("%lld",&m);
 78     for(LL i=0;i<(1<<m);i++)
 79     {
 80         LL x;
 81         scanf("%lld",&x);
 82         A[bit(i)][i]=x*two[bit(i)]%MOD;
 83     }
 84     for(LL i=0;i<(1<<m);i++)
 85     {
 86         LL x;
 87         scanf("%lld",&x);
 88         B[bit(i)][i]=x;
 89     }
 90     for(LL i=0;i<=m;i++) FWT_Xor(A[i],(1<<m));
 91     for(LL i=0;i<=m;i++) FWT_Xor(B[i],(1<<m));
 92     for(LL k=0;k<=m;k++)
 93         for(LL i=k;i<=m;i++)
 94             for(LL j=0;j<(1<<m);j++)
 95                 C[k][j]=(C[k][j]+A[i-k][j]*B[i][j])%MOD;
 96     for(LL i=0;i<=m;i++) IFWT_Xor(C[i],(1<<m));
 97     LL ans=0,mi=1;
 98     for(LL i=0;i<(1<<m);i++)
 99     {
100         ans=(ans+C[bit(i)][i]*mi)%MOD;
101         mi=mi*1526%MOD;
102     }
103     printf("%lld\n",ans);
104     return 0;
105 }

HDU 6057 Kanade's convolution

时间: 2024-11-17 05:54:27

HDU 6057 Kanade's convolution的相关文章

hdu 6057 Kanade&#39;s convolution(子集卷积)

题解: 然后就是接下来如何fwt 也就是如何处理bit(x) - bit(y) = bit(k)这个条件. 其实就是子集卷积. 把bit(x)和bit(y)划分成两个集合,然后就是子集卷积的形式. 这里设两个新的数组 A[bit(y)][y], B[bit(x)][x],代表拆出来的相应数组 然后对这两个数组做fwt,得到其点值表示,然后直接在外层枚举x和y的大小然后做卷积即可. 这样说可能很抽象,其实贴出代码就很清楚了 #include <iostream> #include <vec

hdu 6058 Kanade&#39;s sum(链表)

题目链接:hdu 6058 Kanade's sum 题意: 给你一个n个数的排列,问你全部区间第k大的总和为多少. 题解: 我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x. 我们考虑从小到大枚举xxx,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳kkk次,删除也是O(1)的. 时间复杂度:O(nk) 这题只要是知道能从小到大枚举就好办了. 1 #include<bits/stdc++.h> 2 #defi

HDU 6058 Kanade&#39;s sum —— 2017 Multi-University Training 3

Kanade's sum Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2512    Accepted Submission(s): 1045 Problem Description Give you an array A[1..n]of length n. Let f(l,r,k) be the k-th largest eleme

hdu 6059 Kanade&#39;s trio(trie+容斥)

题目链接:hdu 6059 Kanade's trio 题意: 给你n个数,让你找有多少个(i,j,k),使得i<j<k满足a[i]^a[j]<a[j]^a[k]. 题解: 首先考虑a[i]和a[k],将他们都转换成二进制,对于a[i]和a[k],我们用Bi[p]表示二进制下的a[i]的第p位.考虑a[i]和a[k]二进制不同的最高位,这里假设为p,如果Bi[p]=0,Bk[p]=1,那么Bj[p]要为0,才能使得a[i]^a[j]<a[j]^a[k].(因为p前面的位相同,只有亦

HDU 6058 Kanade&#39;s sum(链表)

http://acm.hdu.edu.cn/showproblem.php?pid=6058 题意:找出所有区间第K大的值之和. 思路: 又有点贡献值的味道,就是考虑当前这个数贡献了几个区间. 然后往左和往右分别找大于当前数的k-1个数,这样就可以确定区间的个数,这要求我们从小到大找 并且找完之后需要删除这个数,用链表来维护. 删除元素的目的是为了加速,保证了当前查找的元素是最小值,所以只需要跳跃寻找k次就可以.具体看代码. 1 #include<iostream> 2 #include<

【链表】2017多校训练3 HDU 6058 Kanade&#39;s sum

acm.hdu.edu.cn/showproblem.php?pid=6058 [题意] 给定一个排列,计算 [思路] 计算排列A中每个数的贡献,即对于每个ai,计算有ni个区间满足ai是区间中的第k大,那么ai对答案的贡献就是ai*ni 以ai为起点,统计ai右边离ai最近的,比ai大的k个数的位置 同理统计左边的位置,组合得到答案 关键是得到比ai大的离ai最近的k个数的位置 因为是排列,所以每个数都不相等,可以记录每个数的位置,然后从小到大枚举ai,这样维护一个双向链表,保证链表中的数就是

HDU 6059 17多校3 Kanade&#39;s trio(字典树)

Problem Description Give you an array A[1..n],you need to calculate how many tuples (i,j,k) satisfy that (i<j<k) and ((A[i] xor A[j])<(A[j] xor A[k])) There are T test cases. 1≤T≤20 1≤∑n≤5∗105 0≤A[i]<230 Input There is only one integer T on fi

hdu 4609 3-idiots 【FFT快(gui)速傅立叶变换】

FFT实现起来挺复杂的,开始用vector,结果发现空间超了,换成数组还是超,删掉了几个后又超时了 sin cos 函数调用次数太多了,改成乘法,还是超时 最后把FFT里的除法运算和模运算优化了一下,终于过了,排的老后面 坑,3843MS,一看时间最少的只有671MS,我都怀疑这是不是同一个算法..为毛差距这么大 #pragma comment(linker, "/STACK:102400000,102400000") #include<iostream> #include

hdu6059 Kanade&#39;s trio 字典树+容斥

转自:http://blog.csdn.net/dormousenone/article/details/76570172 /** 题目:hdu6059 Kanade's trio 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6059 题意:含 N 个数字的 A 数组,求有多少个三元组 (i,j,k) 满足 i<j<k 且 (Ai⊕Aj)<(Aj⊕Ak) 思路: 利用字典树维护前 k-1 个数.当前处理第 k 个数. 显然对于 k 与 i 的