MX 暑假集训 8.5

ウサギの現実は逃げる[术曲初投稿/初音ミク]

我咋啥都不会。学完各种线代和群论再写。

[NOI Online #3 提高组] 魔法值

题意

给定一张 \(n\) 个节点 \(m\) 条边的无向图,初始时点 \(i\) 的点权为 \(a_i\),每个时刻所有点点权同时变化为相邻所有点点权异或和,\(q\) 次询问,每次询问 \(x\) 个时刻后 \(1\) 号节点点权。

\(1\le n,q\le 100,1\le m\le \frac{n(n-1)}{2},1\le a_i,x< 2^{32}\)

solution

\(f_{i,j}\) 表示点 \(i\)\(j\) 个时刻后的点权,转移显然是线性转移,所以可以用 xor-and 矩阵快速幂优化。

但是如果每次询问都用矩阵快速幂求一遍答案时间复杂度是 \(O(n^3q\log x)\) 的,不可接受。

考虑预处理出 \(2^k(0\le k<32)\) 次的转移矩阵,二进制拆分乘起来即可,由于向量与矩阵相乘是 \(O(n^2)\) 的,所以单次询问可以做到 \(O(n^2\log x)\)

由于我们最终只需要求出 \(1\) 号节点的点权,于是预处理矩阵和询问时都可以用 bitset 优化,最终时间复杂度 \(O(\frac{n^3\log x}{\omega }+\frac{n^2 q\log x}{\omega})\)

Code
#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;
#define uint unsigned int
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=100+10;
constexpr int K=100;
constexpr int inf=1e9+10;

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

inline void readu(uint &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

struct Matrix {
	bitset<K> v[K];
	inline Matrix() {f(i,0,99)v[i].reset();}
	inline void init() {f(i,0,99)v[i].set(i);}
}T[35];

inline Matrix operator *(const Matrix &x,const Matrix &y) {
	Matrix res;
	f(i,0,99) for (int k=x.v[i]._Find_first();k!=K;k=x.v[i]._Find_next(k)) res.v[i]^=y.v[k];
	return res;
}
inline void init_qpow(Matrix a) {T[0]=a;f(i,1,31) T[i]=T[i-1]*T[i-1];}

inline bitset<K> operator *(const Matrix &a,const bitset<K> &b) {
	bitset<K> ret;
	f(i,0,99) ret.set(i,(a.v[i]&b).count()&1);
	return ret;
}

int main() {
	int n,m,q;
	static uint a[N];
	read(n);read(m);read(q);
	f(i,0,n-1) readu(a[i]);
	Matrix st;
	f(i,1,m) {
		int x,y;read(x);read(y);
		st.v[x-1].set(y-1);
		st.v[y-1].set(x-1);
	}
	init_qpow(st);
	while (q--) {
		uint x;readu(x);
		bitset<K> tmp;tmp.set(0);
		F(i,31,0) if ((x>>i)&1) tmp=T[i]*tmp;
		uint ans=0;
		for (int i=tmp._Find_first();i!=K;i=tmp._Find_next(i)) ans^=a[i];
		printf("%u\n",ans);
	}
	return 0;
}

Swap Permutation

题意

给定长度为 \(n\) 的排列 \(p\),有 \(m\) 次操作,每次操作会选择两个不同的位置并交换上面元素,定义一个排列的权值 \(f(p)=\sum\limits_{i=1}^{n-1}\left\lvert p_i-p_{i+1}\right\rvert\),求所有不同的操作序列得到的排列的权值和。

\(1\le n,m\le 2\times 10^5\)

solution

拆贡献好题。

考虑枚举一个阈值 \(x\),令 \(c_i=[p_i>x]\) 为第 \(i\) 个位置的颜色,那么由绝对值的定义不难得到,一个排列的权值 \(f(p)=\sum\limits_{x=1}^{n-1}\sum\limits_{i=1}^{n-1}[c_i\ne c_{i+1}]\)

发现对于相邻两个位置 \(i,i+1\),它们颜色可能的状态只有 \((0,0),(0,1),(1,1)\) 三种(\((0,1)\)\((1,0)\) 没有本质区别,所以只算一种),那么在 \(m\) 次操作后,它们可能变成 \((0,0),(0,1),(1,1)\) 中的一种,我们只需要统计变成每种有多少种方案,就可以得到这两个位置的贡献即为变成 \((0,1)\) 的方案数,由于不同位置的方案数是独立的,所以总权值就是每组 \((i,i+1)\) 对应变成 \((0,1)\) 的方案数之和。

\(f_{i,0/1/2}\) 表示 \(i\) 次操作后变成 \((0,0),(0,1),(1,1)\) 的方案数,转移是线性转移,于是可以构造矩阵进行矩阵快速幂优化转移,对于不同位置,最后的转移矩阵是相同的,所以不需要对于每个位置求出转移矩阵,只需要统计出 \((0,0),(0,1),(1,1)\) 位置的个数,并乘上转移矩阵即可。

枚举 \(x\) 并维护 \((0,0),(0,1),(1,1)\) 位置的个数,每次乘上转移矩阵得到当前 \(x\) 的贡献,最后加起来即为答案,时间复杂度 \(O(k^3n\log m)\),其中 \(k=3\)

Code
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
constexpr int N=2e5+10;
constexpr int inf=1e9+10;

constexpr int mod=998244353;
inline int ad(int x,int y) {return ((x+y>=mod)?(x+y-mod):(x+y));}
inline void add(int &x,int y) {x=ad(x,y);}

inline void read(int &x) {
	x=0;
	char ch=getchar();
	while (ch<48) ch=getchar(); 
	while (ch>=48) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

struct Matrix {
	int v[3][3];
	inline Matrix() {f(i,0,2)f(j,0,2)v[i][j]=0;}
	inline void init() {f(i,0,2)v[i][i]=1;}
};

inline Matrix operator *(const Matrix &x,const Matrix &y) {
	Matrix ret;
	f(i,0,2) f(j,0,2) {
		ll sum=0;
		f(k,0,2) sum+=1ll*x.v[i][k]*y.v[k][j];
		ret.v[i][j]=sum%mod;
	}
	return ret;
}

inline Matrix qpow(Matrix a,int b) {
	Matrix res;res.init();
	while (b) {
		if (b&1) res=res*a;
		a=a*a;b>>=1;
	}
	return res;
}

int n,m,sum;
int p[N],mp[N];

inline Matrix solve(int c0,int c1) {
	Matrix ret;
	ret.v[0][0]=ad(mod,(1ll*sum+(c0-2)*2+1)%mod);
	ret.v[1][0]=c0-1;
	ret.v[2][0]=0;
	ret.v[0][1]=c1*2;
	ret.v[1][1]=(1ll*sum+(c0-1)+(c1-1)+1)%mod;
	ret.v[2][1]=c0*2;
	ret.v[0][2]=0;
	ret.v[1][2]=c1-1;
	ret.v[2][2]=ad(mod,(1ll*sum+(c1-2)*2+1)%mod);
	return ret;
}

int main() {
	read(n);read(m);sum=(1ll*(n-2)*(n-3)/2)%mod;
	f(i,1,n) read(p[i]),mp[p[i]]=i;
	Matrix st;st.v[0][2]=n-1;
	ll ans=0;
	f(t,1,n-1) {
		int pos=mp[t];
		if (pos!=1) {
			if (p[pos-1]<t) st.v[0][1]--,st.v[0][0]++;
			else st.v[0][2]--,st.v[0][1]++;
		}
		if (pos!=n) {
			if (p[pos+1]<t) st.v[0][1]--,st.v[0][0]++;
			else st.v[0][2]--,st.v[0][1]++;
		}
		Matrix now=st*qpow(solve(t,n-t),m);
		ans+=now.v[0][1];
	}
	printf("%lld\n",ans%mod);
	return 0;
}
posted @ 2026-08-05 12:00  Ff472130  阅读(4)  评论(0)    收藏  举报