UOJ#346. 【清华集训2017】某位歌姬的故事 动态规划

原文链接www.cnblogs.com/zhouzhendong/p/UOJ346.html

题解

首先按照 $m_i$ 的大小排个序。

如果某一个区间和一个 m 值比他小的区间有交,那么显然可以将这个区间控制的区域删除掉重合的那一段。

如果一个区间被删没了,那么显然答案为 0 。

在这个处理之后,一个区间可能会变得不连续。那么我们就将它前后相连,变成连续的。

接下来问题变成了对每一种权值的区间算答案。

这个东西离散化之后大力DP即可。

注意特判权值为 1 的区间。

写起来好像有点麻烦。

时间复杂度 $O(Tn^2)$ 。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define _SEED_ (‘C‘+‘L‘+‘Y‘+‘A‘+‘K‘+‘I‘+‘O‘+‘I‘)
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch==‘-‘,ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=1005,mod=998244353;
int Pow(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=(LL)x*x%mod)
		if (y&1)
			ans=(LL)ans*x%mod;
	return ans;
}
void Add(int &x,int y){
	if ((x+=y)>=mod)
		x-=mod;
}
void Del(int &x,int y){
	if ((x-=y)<0)
		x+=mod;
}
int n,q,ub;
int Ha[N],hs=0;
int sum[N],vis[N];
struct S{
	int L,R,v;
}a[N],b[N][N];
int c[N];
bool cmp(S a,S b){
	if (a.v!=b.v)
		return a.v<b.v;
	if (a.L!=b.L)
		return a.L<b.L;
	return a.R<b.R;
}
int calc(int n,S *A){
	static S a[N];
	static int kill[N],len[N],pw0[N],pw1[N],iv0[N],iv1[N];
	static int Ha[N],rp[N],dp[N];
	int m=0,hs=0;
	For(i,1,n-1)
		assert(A[i].L<=A[i+1].L);
	clr(kill);
	For(i,1,n)
		For(j,i+1,n)
			if (A[i].L<=A[j].L&&A[j].R<=A[i].R)
				kill[i]=1;
	For(i,1,n)
	 	Ha[++hs]=A[i].L,Ha[++hs]=A[i].R+1;
	sort(Ha+1,Ha+hs+1);
	hs=unique(Ha+1,Ha+hs+1)-Ha-1;
	clr(len);
	For(i,1,n){
		int L=lower_bound(Ha+1,Ha+hs+1,A[i].L)-Ha;
		int R=lower_bound(Ha+1,Ha+hs+1,A[i].R+1)-Ha;
		For(j,L+1,R)
			len[j]=Ha[j]-Ha[j-1];
	}
	For(i,1,n)
		if (!kill[i])
			a[++m]=A[i];
	int v=a[1].v;
	if (v==1)
		return 1;
	n=m;
	pw0[1]=iv0[1]=1;
	For(i,2,hs){
		int tmp=len[i];
		pw0[i]=(LL)pw0[i-1]*Pow(v-1,tmp)%mod;
		pw1[i]=(Pow(v,tmp)-Pow(v-1,tmp)+mod)%mod;
		iv0[i]=Pow(pw0[i],mod-2);
	}
	For(i,1,hs)
		rp[i]=hs+1;
	For(i,1,n){
		a[i].L=lower_bound(Ha+1,Ha+hs+1,a[i].L)-Ha+1;
		a[i].R=lower_bound(Ha+1,Ha+hs+1,a[i].R+1)-Ha;
		For(j,1,a[i].L-1)
			rp[j]=min(rp[j],a[i].R);
	}
	int ans=0;
	clr(dp),dp[1]=1;
	For(i,1,hs){
		For(j,i+1,rp[i])
			Add(dp[j],(LL)dp[i]*pw0[j-1]%mod*iv0[i]%mod*pw1[j]%mod);
		if (rp[i]==hs+1)
			Add(ans,(LL)dp[i]*pw0[hs]%mod*iv0[i]%mod);
	}
	return ans;
}
void Solve(){
	n=read(),q=read(),ub=read();
	clr(Ha),hs=0;
	For(i,1,q){
		a[i].L=read(),a[i].R=read(),a[i].v=read();
		Ha[++hs]=a[i].L,Ha[++hs]=a[i].R+1;
	}
	Ha[++hs]=1,Ha[++hs]=n+1;
	sort(Ha+1,Ha+hs+1);
	hs=unique(Ha+1,Ha+hs+1)-Ha-1;
	Ha[0]=1;
	clr(vis);
	sort(a+1,a+q+1,cmp);
	int cnt=0;
	for (int i=1,j;i<=q;i=j+1){
		j=i,c[++cnt]=0;
		while (j<q&&a[j+1].v==a[i].v)
			j++;
		For(k,1,hs)
			sum[k]=sum[k-1]+(vis[k]?0:Ha[k]-Ha[k-1]);
		For(k,i,j){
			int L=a[k].L=lower_bound(Ha+1,Ha+hs+1,a[k].L)-Ha;
			int R=a[k].R=lower_bound(Ha+1,Ha+hs+1,a[k].R+1)-Ha;
			if (L==R){
				puts("0");
				return;
			}
			c[cnt]++;
			b[cnt][c[cnt]].L=sum[L]+1;
			b[cnt][c[cnt]].R=sum[R];
			b[cnt][c[cnt]].v=a[k].v;
		}
		For(k,i,j)
			For(t,a[k].L+1,a[k].R)
				vis[t]=1;
	}
	int ans=1;
	For(i,2,hs)
		if (!vis[i])
			ans=(LL)ans*Pow(ub,Ha[i]-Ha[i-1])%mod;
	For(i,1,cnt)
		ans=(LL)ans*calc(c[i],b[i])%mod;
	cout<<ans<<endl;
}
int main(){
	int T=read();
	while (T--)
		Solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ346.html

时间: 2024-08-06 03:30:34

UOJ#346. 【清华集训2017】某位歌姬的故事 动态规划的相关文章

[LOJ#2331]「清华集训 2017」某位歌姬的故事

[LOJ#2331]「清华集训 2017」某位歌姬的故事 试题描述 IA是一名会唱歌的女孩子. IOI2018就要来了,IA决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符,第iii个音符的音高为 \(h_i\).IA的音域是 \(A\),她只能唱出 \(1\sim A\) 中的正整数音高.因此 \(1\le h_i\le A\). 在写歌之前,IA需要确定下这首歌的结构,于是她写下了 \(Q\) 条限制,其中第 \(i\) 条为:编号在 \(l_i\) 到 \(r_

2017.11.26【清华集训2017】模拟

T1 5483. [清华集训2017模拟11.26]简单路径T2 5484. [清华集训2017模拟11.26]快乐树T3 5485. [清华集训2017模拟11.26]字符串 T1 结论题,结论很显然任意两条路径权异或后,会将两条路径的交的贡献删去.然后用个桶存一下出现过的异或和,暴力判一下就可以了 code 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主 试题描述 "A fight? Count me in!" 要打架了,算我一个. "Everyone, get in here!" 所有人,都过来! 小Y是一个喜欢玩游戏的OIer.一天,她正在玩一款游戏,要打一个Boss. 虽然这个Boss有 \(10^{100}\) 点生命值,但它只带了一个随从--一个只有 \(m\) 点生命值的"恐怖的奴隶主". 这个"恐怖的奴隶主&qu

[LOJ#2328]「清华集训 2017」避难所

[LOJ#2328]「清华集训 2017」避难所 试题描述 "B君啊,你当年的伙伴都不在北京了,为什么你还在北京呢?" "大概是因为出了一些事故吧,否则这道题就不叫避难所了." "唔,那你之后会去哪呢?" "去一个没有冬天的地方." 对于一个正整数 \(n\),我们定义他在 \(b\) 进制下,各个位上的数的乘积为 \(p = F(n, b)\). 比如 \(F(3338, 10) = 216\). 考虑这样一个问题,已知 \

[LOJ#2327]「清华集训 2017」福若格斯

[LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最左边的两个格子上各有一个向右的青蛙,最右边的两个格子上各有一个向左的青蛙. 每次移动可以选取一个青蛙,向这只青蛙的前方移动一格到空格子中或跳过前方的一个不同朝向的青蛙并移动到空格子中. 为了使你更好地理解这个游戏,我们下发了一个游戏demo作为参考(注意:这个demo中的棋盘大小和题目中并不相同).

「清华集训 2017」某位歌姬的故事

题目链接 问题分析 吐槽一下这个预处理比DP还长的题-- 首先对限制从小到大排序,然后不难发现对于每一种大小限制都是独立的.离散后考虑\(F[i][j]\)表示以\(i\)结尾,上一个音高为限制大小的位置\(j\)的方案种数.不难发现对于一些右端点相同的限制,左端点最右的限制才有效.这样就可以\(n^2\)动规了. 由于要离散化,所以细节很多. 参考程序 程序没有显式的离散化,并且大量使用结构体,所以又慢又长. #include <bits/stdc++.h> #define LL long

UOJ#339. 【清华集训2017】小 Y 和二叉树 贪心

原文链接 www.cnblogs.com/zhouzhendong/p/UOJ339.html 前言 好久没更博客了,前来更一发. 题解 首先,我们考虑一个子问题:给定根,求出最小中序遍历. 如果根节点有一个儿子,那么,我们需要比较根节点和 儿子的最小中序遍历的第一个元素,选择较优的一方放在前面. 如果根节点有两个儿子,那么,我们必然选择最小中序遍历较小的儿子放在左儿子. 由于所有节点编号互不相同,所以我们在比较两个部分的字典序时,只关注第一个元素的大小. 可以发现,一个有两个儿子的节点是不可能

线性基 uoj 36 清华集训2014 玛里苟斯

http://uoj.ac/problem/36 感觉挺可做的但是不会.. \(k=1\)按位扫就好了 出现\(1\)概率就是\(0.5\) \(k=2\)要特殊处理 设xor后的数是\(b_1 b_2 \dots b_n\) 计算平方贡献就好了\(\sum_{i,j}b_i b_j 2^{i+j}*p\) \(p\)存在一位\(i\),\(j\)不同的话是1/4 否则就是1/2 \(k\geq3\) 首先要知道随机选数的话 如果维护的集合可以通过xor算子得到\(x\) 那么\(x\)与答案无

「清华集训 2017」无限之环

无限之WA https://www.luogu.org/problemnew/show/P4003 本题如果知道是网络流的话,其实建图不算特别神奇,但是比较麻烦. 数据范围过大,插头dp不能处理,而且是一个网格图,考虑网络流. 先看是不是二分图? 每个格子只会和相邻四个格子发生关系 所以,黑白染色正好. i+j为偶数左部点,i+j为奇数右部点 不漏水是什么? 每个管道的四个口都能和别的接好. S向左,右向T连口数的容量,费用为0的边 考虑怎么能把左右连在一起. 考虑要上下左右四个方向匹配,那么必