【模拟赛】疑惑矩阵(卢卡斯定理,高维前缀和)

背景

[ 🤔 🤔 ⋯ 🤔 🤔 🤔 ⋯ 🤔 ⋮ ⋮ ⋱ ⋮ 🤔 🤔 ⋯ 🤔 ] \left[ \begin{matrix} 🤔&🤔&\cdots&🤔\\ 🤔&🤔&\cdots&🤔\\ \vdots&\vdots&\ddots&\vdots \\ 🤔&🤔&\cdots&🤔\\ \end{matrix} \right] 🤔🤔🤔🤔🤔🤔🤔🤔🤔

题面

在这里插入图片描述
在这里插入图片描述
1 s, 64 mb .

题解

不难发现结论: f K , i = ⨁ j = 0 K − 1 ( K − 1 j ) a i + j f_{K,i}=\bigoplus_{j=0}^{K-1}{K-1\choose j}a_{i+j} fK,i=j=0K1(jK1)ai+j

然后,肯定不能用卷积,我们要换个想法。

首先这个组合数是可以取模 2 的,因此动用Lucas定理, ( K − 1 j ) ≡ [ j   a n d   ( K − 1 ) = j ] {K-1\choose j}\equiv [j{\rm~and~}(K-1)=j] (jK1)[j and (K1)=j].

也就是说, f ( K , i ) f(K,i) f(K,i) 就等于所有 a i + j a_{i+j} ai+j 的异或和,满足 j j j 的二进制表示是 K − 1 K-1 K1 的子集。

这是个高维前缀和的形式,我们可以通过类似倍增的预处理的方式解决。

d p [ i ] [ p ] dp[i][p] dp[i][p] 表示所有 a i + j a_{i+j} ai+j 的异或和,满足 j j j 的二进制表示是 K − 1 K-1 K1 只保留最低 p p p 位的子集。

那就很好转移了, d p [ i ] [ 0 ] = a i dp[i][0]=a_{i} dp[i][0]=ai ,若 K − 1 K-1 K1 p p p 位为 0, d p [ i ] [ p ] = d p [ i ] [ p − 1 ] dp[i][p]=dp[i][p-1] dp[i][p]=dp[i][p1],否则
d p [ i ] [ p ] = d p [ i ] [ p − 1 ] ⊕ d p [ i + 2 p − 1 ] [ p − 1 ] dp[i][p]=dp[i][p-1]\oplus dp[i+2^{p-1}][p-1] dp[i][p]=dp[i][p1]dp[i+2p1][p1]

第二维可以压缩掉,空间复杂度 O ( n ) O(n) O(n),时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

CODE

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 3000005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define UIN unsigned int
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
//#define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

int n,m,s,o,k;
UIN dp[MAXN];
int main() {
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	n = read(); m = read()-1;
	dp[1] = read();
	for(int i = 2;i <= n;i ++) {
		dp[i] = 1145141u*dp[i-1] + 1919u*i + 810u;
	}
	int nm = m;
	while(nm) {
		for(int i = 1;i+lowbit(nm) <= n;i ++) {
			dp[i] ^= dp[i+lowbit(nm)];
		}
		nm -= lowbit(nm);
	}
	UIN ans = 0;
	for(int i = 1;i <= n-m;i ++) {
		UIN f = dp[i] ^ i;
		ans += f*i;
	}
	AIput(ans,'\n');
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值