题解 颜色

传送门

答案显然是 \(\prod\limits_i(cnt_i+1)\)

首先 \(O(n\sqrt n\log n)\) 的做法有若干
包括但不限于根号分治+可持久化数组

然后来考虑一个时间 \(O(n\sqrt n)\),空间 \(O(n^2)\) 的分块
预处理出每两个块之间的答案及每种颜色的出现次数
出现次数若使用 set 等维护也是 \(O(n\sqrt n\log n)\)
然后考虑莫队的在线化改造
其实就是上面的做法卡了一下空间分块,其余部分和上面一样但是注意到每种颜色的出现次数是可以前缀和做差的
所以其实只需要 \(O(n\sqrt n)\) 的空间

然后记一下带修莫队的在线化改造:
如果只追求复杂度正确,完全按照上面的方法来就可以做到完全跑满的 \(O(n^{\frac{5}{3}})\)
然后想想怎么让它跑不满
那么修改的时候只修改 \(O(n^{\frac{1}{3}})\) 个关键点处的信息(而非答案)
对每个块记录上一次更新答案的时间,到需要用的时候再更新即可
因为块中的答案是过时的,但维护的信息已经是最新的,所以更新答案要(在时间轴上)倒着更新

点击查看代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("avx", "sse")
#pragma GCC optimize("inline")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#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, q;
int col[N];
const ll mod=998244353;
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;}

namespace force{
	ll ans;
	int cnt[N];
	void solve() {
		for (int i=1,l,r; i<=q; ++i) {
			l=read()^ans; r=read()^ans; ans=1;
			for (int j=1; j<=n; ++j) cnt[j]=1;
			for (int j=l; j<=r; ++j) ++cnt[col[j]];
			for (int j=1; j<=n; ++j) ans=ans*cnt[j]%mod;
			printf("%lld\n", ans);
		}
	}
}

namespace task1{
	int sta[N], top;
	ll inv[N<<1], dat[325][325];
	int sum[325][N], bel[N], ls[N], rs[N], cnt[N], sqr;
	void solve() {
		sqr=sqrt(n);
		for (int i=1; i<=n; ++i) bel[i]=(i-1)/sqr+1;
		for (int i=1; i<=n; ++i) rs[bel[i]]=i;
		for (int i=n; i; --i) ls[bel[i]]=i;
		inv[0]=inv[1]=1;
		for (int i=2; i<=2*n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=1; i<=n; ++i) cnt[i]=1;
		for (int i=1; i<=bel[n]; ++i) {
			ll val=1;
			dat[i][i]=1;
			for (int j=rs[i]+1; j<=n; ++j) {
				val=val*inv[cnt[col[j]]++]%mod;
				val=val*cnt[col[j]]%mod;
				if (j==rs[bel[j]]) dat[i][bel[j]]=val;
			}
			for (int j=rs[i]+1; j<=n; ++j) --cnt[col[j]];
		}
		for (int i=1; i<=n; ++i) {
			++cnt[col[i]];
			if (i==rs[bel[i]]) for (int j=1; j<=n; ++j) sum[bel[i]][j]=cnt[j];
		}
		ll ans=0;
		for (int i=1; i<=n; ++i) cnt[i]=1;
		// cout<<"bel: "; for (int i=1; i<=n; ++i) cout<<bel[i]<<' '; cout<<endl;
		for (int i=1,l,r,ql,qr; i<=q; ++i) {
			ql=read()^ans, qr=read()^ans;
			// cout<<"i: "<<i<<' '<<ql<<' '<<qr<<endl;
			ans=dat[bel[ql]][bel[qr]];
			// cout<<"ans: "<<ans<<endl;
			l=rs[bel[ql]]+1, r=rs[bel[qr]];
			// cout<<"lr: "<<l<<' '<<r<<endl;
			while (l>ql) {
				--l;
				// cout<<"l: "<<l<<endl;
				int now=sum[bel[qr]][col[l]]-sum[bel[ql]][col[l]]+cnt[col[l]];
				// cout<<"now: "<<now<<endl;
				// cout<<"inv: "<<now<<endl;
				ans=ans*inv[now++]%mod;
				++cnt[col[l]]; sta[++top]=col[l];
				ans=ans*now%mod;
				// cout<<"mul: "<<now<<endl;
			}
			while (r>qr) {
				// cout<<"r: "<<r<<endl;
				int now=sum[bel[qr]][col[r]]-sum[bel[ql]][col[r]]+cnt[col[r]];
				// cout<<"now: "<<now<<endl;
				// cout<<"inv: "<<now<<endl;
				ans=ans*inv[now--]%mod;
				--cnt[col[r]]; sta[++top]=col[r];
				ans=ans*now%mod;
				// cout<<"mul: "<<now<<endl;
				--r;
			}
			printf("%lld\n", ans);
			while (top) cnt[sta[top--]]=1;
		}
	}
}

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

	n=read();
	for (int i=1; i<=n; ++i) col[i]=read();
	q=read();
	// force::solve();
	task1::solve();

	return 0;
}
posted @ 2022-07-30 15:21  Administrator-09  阅读(4)  评论(0编辑  收藏  举报