题解 亿点整理

传送门

神仙题!
听说大力卡时网络流匹配能过

考虑就是要找一个排列 \(p\) 使 \(\sum f_{i, p_i}\equiv 0 \pmod k\)
考虑将矩阵中的每个元素写成集合幂级数 \(x^{f_{i, j}}\),当 \(f_{i, j}=0\) 时这个元素就直接赋为 0
然后将乘法定义为 \(\bmod k\) 意义下的循环卷积
那么求出行列式,则有解的条件是 \([x^0]\det\neq0\)……吗?
显然不是,因为行列式前面 \((-1)^{\pi(p)}\) 的系数可能相消成 0
那么考虑给多项式每项系数再乘个随机权值,这样正确率就比较高了
直接多项式操作的复杂度是 \(O(n^4\log n)\) 的,过不去

考虑怎么在更优秀的复杂度内求出 \(\det\)
发现这是个 \(k-1\) 次多项式,那么求出 \(k\) 个点值带进去 lagrange 插值即可

然而还有更简单的做法
考虑利用单位根反演的一些性质
发现我们要选 \(k\) 个点值带进去,要求的是 \([x^0]\det\) 是否为 0
利用 \([n|1]=\frac{1}{n}\sum\limits_{i=0}^{n-1}\omega_n^{i}\)
考虑将单位根的 \([0, k-1]\) 次方当做 \(x\) 带进去
令多项式系数为 \(b_0\sim b_{k-1}\),点值为 \(a_0\sim a_{k-1}\)

\[a_i=\sum x_i^j b_j \]

那么

\[\begin{aligned}\sum a_i&=\sum b_i\sum x_j^i \\ &=b_0\times k+\sum\limits_{i\geqslant 1}b_i\sum x_j^i \end{aligned} \]

发现 \(\sum x_j^i=\sum\limits_{j=0}^{k-1}\omega_n^{ij}=[k|i]=0\)
所以只要将点值简单加和判断是否为 0 就可以了
p.s. 感谢可爱雨兔兔和 zxy 的模数表!
复杂度 \(O(n^4)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 110
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
int a[N][N];

namespace force{
	bool f[1<<20][200];
	void solve() {
		// cout<<double(sizeof(f))/1000/1000<<endl;
		int lim=1<<n;
		f[0][0]=1;
		for (int s=0,cnt; s<lim; ++s) {
			cnt=__builtin_popcount(s);
			for (int i=0; i<k; ++i) if (f[s][i])
				for (int j=0; j<n; ++j) if (!(s&(1<<j)) && a[cnt][j]!=-1)
					f[s|(1<<j)][(i+a[cnt][j])%k]|=f[s][i];
		}
		puts(f[lim-1][0]?"Yes":"No");
	}
}

namespace task{
	ll rnd[N][N], rt, mod, w;
	const int M[] = { 0, 0, 1073741827, 1073741827, 1073741833, 1073741831, 1073741827, 1073741831, 1073741833, 1073741833, 1073741831, 1073741857, 1073741833, 1073741839, 1073741831, 1073741971, 1073741857, 1073742169, 1073741833, 1073741833, 1073742361, 1073741971, 1073741857, 1073741891, 1073741833, 1073742851, 1073741839, 1073741833, 1073742209, 1073742053, 1073741971, 1073742289, 1073741857, 1073741857, 1073742169, 1073741831, 1073741833, 1073742073, 1073741833, 1073741839, 1073742361, 1073742113, 1073741971, 1073741993, 1073741857, 1073742391, 1073741891, 1073742073, 1073741857, 1073742391, 1073742851, 1073742169, 1073741969, 1073742053, 1073741833, 1073742671, 1073742209, 1073741833, 1073742053, 1073741827, 1073742361, 1073747621, 1073742289, 1073742391, 1073741953, 1073741891, 1073741857, 1073742403, 1073742169, 1073742259, 1073741831, 1073745781, 1073741833, 1073743861, 1073742073, 1073743051, 1073741833, 1073742209, 1073741839, 1073742721, 1073742721, 1073741833, 1073742113, 1073745769, 1073742517, 1073743291, 1073741993, 1073742169, 1073741857, 1073743883, 1073742391, 1073742671, 1073742673, 1073742289, 1073742073, 1073744911, 1073741857, 1073742277, 1073742391, 1073742517, 1073743501 };
	const int G[] = { 0, 0,  2,  2, 5, 13, 2, 13, 5, 5,  13, 5, 5,  3, 13, 2,  5, 7, 5,  5, 7, 2, 5, 6, 5, 2, 3, 5,  3,  2, 2, 37, 5, 5,  7, 13, 5,  5, 5,  3, 7,  5,  2, 3, 5,  6, 6, 5, 5, 6, 2, 7, 3, 2,  5,  7, 3, 5,  2, 2,  7, 2,  37, 6, 10, 6, 5,  2,  7, 2, 13, 2, 5, 6, 5, 2, 5, 3, 3, 11, 11, 5, 5, 7,  6, 2,  3, 7,  5,  2, 6,  7, 5,  37, 5, 6, 5,  5, 6, 6, 2 };
	inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
	struct matrix{
		int n, m;
		ll a[N][N];
		matrix() {n=m=0; memset(a, 0, sizeof(a));}
		matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
		void resize(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
		inline ll* operator [] (int t) {return a[t];}
		inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=n; ++j) cout<<setw(10)<<a[i][j]<<' '; cout<<endl;}cout<<endl;}
		ll qdet() {
			ll ans=1;
			for (int i=1; i<=n; ++i) {
				for (int j=i+1; j<=n; ++j) {
					while (a[j][i]) {
						ll t=a[i][i]/a[j][i];
						for (int k=i; k<=m; ++k) a[i][k]=(a[i][k]-a[j][k]*t)%mod;
						swap(a[i], a[j]); ans*=-1;
					}
				}
			}
			for (int i=1; i<=n; ++i) ans=ans*a[i][i]%mod;
			return ans;
		}
	}mat;
	void solve() {
		random_device seed;
		mt19937 rand(seed());
		rt=G[k]; mod=M[k]; w=qpow(rt, (mod-1)/k);
		ll x=w, sum=0;
		mat.resize(n, n);
		for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) rnd[i][j]=rand()%mod;
		for (int i=1; i<=k; ++i,x=x*w%mod) {
			// cout<<"x: "<<x<<endl;
			for (int j=1; j<=n; ++j)
				for (int k=1; k<=n; ++k)
					mat[j][k]=~a[j][k]?qpow(x, a[j][k])*rnd[j][k]%mod:0;
			// mat.put();
			sum=(sum+mat.qdet())%mod;
		}
		puts(sum?"Yes":"No");
	}
}

signed main()
{
	freopen("sort.in", "r", stdin);
	freopen("sort.out", "w", stdout);

	n=read(); k=read();
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) a[i][j]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-01 08:06  Administrator-09  阅读(2)  评论(0编辑  收藏  举报