0502 zr模擬賽

A

在這裏插入圖片描述

乍一看 就是一個需要插入刪除的線性基,裏面 2^未確認的位數 就是連通塊答案。

然後不會刪除,所以寫個線段樹分治。

正解是離線,對於線性基每個數維護有效的最後時間,插入的時候更新一下讓每一位的有效時間最大。然後查詢的時候就看有多少位的最後有效時間>=i當前時間。這樣就是一個log的。

女少

#include<bits/stdc++.h>
using namespace std;
inline void read(int &x) {
	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
	for(x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 2000005;
int n, m, a[MAXN], ed[MAXN];
map<int,int>pre;
int b[30], lst[30];
inline void ins(int x, int t) {
	for(int i = n-1; i >= 0; --i)
		if(x>>i&1) {
			if(!b[i]) { b[i] = x, lst[i] = t; return; }
			if(t > lst[i]) swap(lst[i], t), swap(b[i], x);
			x ^= b[i];
		}
}
int main () {
	freopen("A.in", "r", stdin);
	freopen("A.out", "w", stdout);
	read(n), read(m);
	for(int i = 1, op; i <= m; ++i) {
		read(op), read(a[i]);
		if(op == 1) pre[a[i]] = i, ed[i] = m;
		else ed[pre[a[i]]] = i-1;
	}
	int ans = 0;
	for(int i = 1; i <= m; ++i) {
		if(ed[i]) ins(a[i], ed[i]);
		int sum = n;
		for(int j = 0; j < n; ++j)
			if(b[j] && lst[j] >= i) --sum;
		ans ^= 1<<sum;
	}
	printf("%d\n", ans);
	return 0;
}

B

在這裏插入圖片描述

直接放題解,有點傻逼的題…不會。
在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 15 + 2;
const int MAXS = (1<<15) + 2;
const int mod = 1e9 + 7;
int n, m, a[MAXN], r[MAXN], rk[MAXN], id[MAXN], dp[MAXN][MAXS];
bool err[MAXS]; int lst[MAXS];
inline bool cmp(int i, int j) { return r[i] < r[j]; }
int main () {
	freopen("B.in", "r", stdin);
	freopen("B.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; ++i) scanf("%d", &r[i]), ++r[i], id[i] = i;
	sort(id, id+n, cmp);
	for(int i = 0; i < n; ++i) a[i] = r[id[i]], rk[id[i]] = i;
	for(int x, y; m--; ) {
		scanf("%d%d", &x, &y);
		x = rk[x-1], y = rk[y-1];
		for(int i = 0; i < (1<<n); ++i)
			err[i] |= i>>x&i>>y&1;
	}
	for(int i = 1; i < (1<<n); ++i) lst[i] = __builtin_ctz(i);
	dp[0][(1<<n)-1] = 1;
	for(int i = 0; i < n; ++i)
		for(int s = 0; s < (1<<n); ++s) if(dp[i][s])
			for(int k = s; k; k = (k-1)&s)
				if(!err[k] && (k>>lst[s]&1) && a[lst[k]] > i)
					dp[i+1][s^k] = (dp[i+1][s^k] + 1ll*(a[lst[k]]-i)*dp[i][s]) % mod;
	int ans = 0;
	for(int i = 1; i <= n; ++i) ans = (ans + 1ll * i * dp[i][0]) % mod;
	printf("%d\n", ans);
}

C

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
上面公式有點小問題,但是可以理解。

然後對於小於根號的質數的冪直接暴力前綴和求貢獻。時間複雜度是這樣的:
在這裏插入圖片描述
大質數就直接莫隊計算。
在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int mod = 998244353;
int n, m, val, inv[MAXN], a[MAXN], bel[MAXN], ans[MAXN], cnt[MAXN], sum[MAXN], mn[MAXN], num[MAXN];
vector<int>pw[MAXN], ipw[MAXN];
struct node { int l, r, id; }q[MAXN];
inline int qpow(int a, int b) {
	int re = 1;
	for(; b; b>>=1, a=1ll*a*a%mod)if(b&1) re=1ll*re*a%mod;
	return re;
}
inline bool cmp(const node &A, const node &B) {
	return bel[A.l] == bel[B.l] ? (bel[A.l] & 1) ? A.r < B.r : A.r > B.r : bel[A.l] < bel[B.l];
}
inline void add(int i) {
	int x = num[i];
	if(x) val = 1ll * val * pw[x][cnt[x]++] % mod;
}
inline void del(int i) {
	int x = num[i];
	if(x) val = 1ll * val * ipw[x][--cnt[x]] % mod;
}
int main () {
	freopen("C.in", "r", stdin);
	freopen("C.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
		bel[i] = (i-1)/400 + 1;
		int x = a[i];
		for(int j = 2; j*j <= x; ++j) if(!(x%j)) {
			int now = 1;
			while(!(x%j)) ++cnt[now *= j], x /= j;
		}
		if(x > 1) ++cnt[x];
		if(1ll * x * x > 100000) num[i] = x;
	}
	for(int i = 2; i <= 100000; ++i) {
		for(int j = i; j <= 100000; j += i) if(!mn[j]) mn[j] = i;
		pw[i].push_back(mn[i]); inv[i] = qpow(i, mod-2);
		ipw[i].push_back(inv[mn[i]]);
		for(int j = 1; j <= cnt[i]; ++j)
			pw[i].push_back(1ll * pw[i][j-1] * pw[i][j-1] % mod),
			ipw[i].push_back(1ll * ipw[i][j-1] * ipw[i][j-1] % mod);
	}
	for(int i = 1; i <= m; ++i) scanf("%d%d", &q[i].l, &q[i].r), ans[q[i].id = i] = 1;
	sort(q + 1, q + m + 1, cmp);
	for(int i = 2; i <= 100000; ++i) if(1ll * mn[i] * mn[i] <= 100000 && cnt[i]) {
		for(int j = 1; j <= n; ++j)
			sum[j] = sum[j-1] + (a[j] % i == 0);
		for(int j = 1; j <= m; ++j)
			ans[q[j].id] = 1ll * ans[q[j].id] * pw[i][sum[q[j].r]-sum[q[j].l-1]] % mod * inv[mn[i]] % mod;
	}
	memset(cnt, 0, sizeof cnt); val = 1;
	int l = 1, r = 0;
	for(int i = 1; i <= m; ++i) {
		while(l > q[i].l) add(--l);
		while(r < q[i].r) add(++r);
		while(l < q[i].l) del(l++);
		while(r > q[i].r) del(r--);
		ans[q[i].id] = 1ll * ans[q[i].id] * val % mod;
	}
	for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章