LOJ2331 某位歌姬的故事 和 CF1327F AND Segments

LOJ2331 某位歌姬的故事

IA 是一名会唱歌的女孩子。

IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿。这首歌一共有 \(n\) 个音符,第 \(i\) 个音符的音高为 \(h_i\)。IA 的音域是 \(A\),她只能唱出 \(1\sim A\) 中的正整数音高。因此 \(1\le h_i\le A\)

在写歌之前,IA 需要确定下这首歌的结构,于是她写下了 \(Q​\) 条限制,其中第 \(i​\) 条为:编号在 \(l_i​\)\(r_i​\) 之间的音符的最高音高为 \(m_i​\)。在确定了结构之后,她就可以开始写歌了。不过她还是想知道,一共有多少种可能的歌曲满足她的所有限制?她听说你还有 9 个月就要去 IOI 了,于是希望你帮她计算一下这个值。

\(Q\leq 500\)

题解

仓鼠《动态规划选讲》。

\(max_{l≤i≤r}\{A_i\} = h\)等价于\(∀l ≤ i ≤ r, A_i ≤ h\)\(∃l ≤ i ≤ r, A_i = h\)

求出每个点的上限\(up_i\)。可以发现,\(∃l ≤ i ≤ r, A_i = h\)\(i\)只能由上限\(up_i = h\)的点来贡献

所以对于每个\(h\)的限制以及上限为\(h\)的点单独拿出来DP,满足每个限制区间中至少有一个点达到上限即可。

时间复杂度\(O(Q^3)\),可以利用前缀和优化到\(O(Q^2)\)

CO int N=1e3+10;
int m,n,A;
vector<int> num,val;
struct node {int l,r,m;} a[N];
int len[N],lim[N];
int t[N],l[N],f[N][N];

int solve(int x){
	int tot=0;
	for(int i=1;i<(int)num.size();++i)if(lim[i]==x){
		t[++tot]=i,l[tot]=0;
		for(int j=0;j<=tot;++j) f[tot][j]=0;
	}
	for(int i=1;i<=n;++i)if(a[i].m==x){
		if(!tot) return 0;
		int L=lower_bound(t+1,t+tot+1,a[i].l)-t;
		int R=lower_bound(t+1,t+tot+1,a[i].r)-t-1;
		l[R]=max(l[R],L);
	}
	f[0][0]=1;
	for(int i=1;i<=tot;++i){
		int v1=fpow(x,len[t[i]]),v2=fpow(x-1,len[t[i]]);
		for(int j=0;j<i;++j)if(f[i-1][j]){
			if(j>=l[i]) f[i][j]=add(f[i][j],mul(f[i-1][j],v2));
			f[i][i]=add(f[i][i],mul(f[i-1][j],add(v1,mod-v2)));
		}
	}
	int ans=0;
	for(int i=0;i<=tot;++i) ans=add(ans,f[tot][i]);
	return ans;
}
void real_main(){
	read(m),read(n),read(A);
	num={1,m+1},val.clear();
	for(int i=1;i<=n;++i){
		read(a[i].l),read(a[i].r),read(a[i].m);
		num.push_back(a[i].l),num.push_back(++a[i].r);
		val.push_back(a[i].m);
	}
	sort(num.begin(),num.end());
	num.erase(unique(num.begin(),num.end()),num.end());
	sort(val.begin(),val.end());
	val.erase(unique(val.begin(),val.end()),val.end());
	for(int i=1;i<(int)num.size();++i) len[i]=num[i]-num[i-1];
	for(int i=1;i<=n;++i){
		a[i].l=lower_bound(num.begin(),num.end(),a[i].l)-num.begin()+1;
		a[i].r=lower_bound(num.begin(),num.end(),a[i].r)-num.begin()+1;
	}
	for(int i=1;i<(int)num.size();++i) lim[i]=A+1;
	for(int i=1;i<=n;++i)
		for(int j=a[i].l;j<a[i].r;++j)
			lim[j]=min(lim[j],a[i].m);
	
	int ans=1;
	for(int i=1;i<=(int)val.size();++i){
		ans=mul(ans,solve(val[i-1]));
		if(ans==0) {puts("0"); return;}
	}
	for(int i=1;i<(int)num.size();++i)
		if(lim[i]==A+1) ans=mul(ans,fpow(A,len[i]));
	printf("%d\n",ans);
}
int main(){
	for(int T=read<int>();T--;) real_main();
	return 0;
}

CF1327F AND Segments

You are given three integers \(n, k, m\) and \(m\) conditions \((l_1, r_1, x_1), (l_2, r_2, x_2), \dots, (l_m, r_m, x_m)\).

Calculate the number of distinct arrays \(a\), consisting of \(n\) integers such that:

  • \(0 \le a_i < 2^k\) for each \(1 \le i \le n\);

  • bitwise AND of numbers \(a[l_i] \& a[l_i + 1] \& \dots \& a[r_i] = x_i\) for each \(1 \le i \le m\).

Two arrays \(a\) and \(b\) are considered different if there exists such a position \(i\) that \(a_i \neq b_i\).

The number can be pretty large so print it modulo \(998244353\).

\(1 \le n \le 5 \cdot 10^5, 1 \le k \le 30, 0 \le m \le 5 \cdot 10^5\)

题解

显然每位独立,分开计算,用乘法原理合并。

如果\(x_i=1\),那么毫无疑问区间内所有数都是\(1\)

如果\(x_i=0\),那么区间内至少有一个数为\(0\)。这个限制跟上一道题一模一样。

利用前缀和把DP优化到线性。时间复杂度\(O(n\log n)\)

CO int N=5e5+10;
struct node {int l,r,x;} a[N];
int V[N],L[N],S[N];
 
int solve(int n){
	fill(S+1,S+n+1,0),S[0]=1;
	int lim=-1;
	for(int i=1;i<=n;++i){
		if(!V[i]){
			int sum=add(S[i-1],mod-(lim>=0?S[lim]:0));
			lim=max(lim,L[i]-1);
			S[i]=add(S[i-1],sum);
		}
		else S[i]=S[i-1];
	}
	return add(S[n],mod-(lim>=0?S[lim]:0));
}
 
int fa[N];
 
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
	int n=read<int>(),K=read<int>(),m=read<int>();
	for(int i=1;i<=m;++i) read(a[i].l),read(a[i].r),read(a[i].x);
	int ans=1;
	for(int c=0;c<K;++c){
		for(int i=1;i<=n;++i) fa[i]=i;
		fill(V+1,V+n+1,0);
		for(int i=1;i<=m;++i)if(a[i].x>>c&1)
			for(int p=find(a[i].r);p>=a[i].l;p=find(p))
				V[p]=1,fa[p]=p-1;
		fill(L+1,L+n+1,0);
		bool flag=0;
		for(int i=1;i<=m;++i)if(~a[i].x>>c&1){
			int p=find(a[i].r);
			if(!p) {flag=1;break;}
			L[p]=max(L[p],a[i].l);
		}
		if(flag) {ans=0;break;}
		ans=mul(ans,solve(n));
	}
	printf("%d\n",ans);
	return 0;
}

posted on 2020-04-14 09:19  autoint  阅读(199)  评论(0编辑  收藏  举报

导航