专栏文章

P12789 [ICPC 2024 Yokohama R] Peculiar Protocol

P12789题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mip3as0d
此快照首次捕获于
2025/12/03 05:28
3 个月前
此快照最后确认于
2025/12/03 05:28
3 个月前
查看原文
存在一个显然的性质:对于任意一个区间 [l,r]\left [ l,r \right ] ,设用其中元素至多能参加 xx 场婚礼,那么对于任意 yxy \le x,都可以找到一种合法的方案。
所以我们可以统计每个区间能参加婚礼的最大次数,并借助这个判定一个区间能否完全利用。
转移是简易的,因为只关心最大次数,所以只需要枚举断点,判断剩下元素总和对 dd 取模是否为 rr 即可。
为了判定简便,可以事先预处理达到每个余数至少要举办几场婚礼。
其余细节可以见代码。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
template <typename T>
void in(T &x){
	char c=getchar(), f=1;
	while ((c<'0' || c>'9') && c!='-') c=getchar();
	if (c=='-') f=-1, c=getchar();
	for (x=0; c>='0' && c<='9'; c=getchar())
		x=x*10+c-'0';
	x*=f;
}
const int N=505;
int n,d,r,al,dp[N][N];
long long s[N],f[N][N];
unordered_map<int,int>p;
int main(){
	in(n);in(d);in(r);
	for(int i=1;i<=n;i++){
		al+=r;if(al>=d)al-=d;
		if(p.count(al))break;
		p[al]=i;
	}
	for(int i=1;i<=n;i++){
		in(s[i]);
		if(s[i]%d==r)dp[i][i]=1,f[i][i]=s[i]/d;
		s[i]+=s[i-1];
	}
	for(int l=1;l<n;l++){
		for(int i=n-l;i;i--){
			int j=i+l,mx=0;
			for(int k=i;k<j;k++){
				f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
				mx=max(mx,dp[i][k]+dp[k+1][j]);
			}
			long long xx=(s[j]-s[i-1])%d;
			if(p.count(xx)&&p[xx]==mx+1)mx++;//如果res=0似乎会使mx变大(用0张巻白吃?)
			//但res=0如果出现,就一定是最后一项,也就是所有可达余数都已经能被计算出来了,多统计无影响
			dp[i][j]=mx;
			if(p.count(xx)&&mx>=p[xx])f[i][j]=max(f[i][j],(s[j]-s[i-1]-p[xx]*1ll*r)/d);
		}
	}
	cout<<f[1][n];
	return 0;
}
/*
dp[i][j]->区间[i,j]至多能参加几场婚礼
f[i][j]->区间[i,j]的答案
显然,只要需求可达且不超过dp[i][j],都能凑出来
*/

评论

2 条评论,欢迎与作者交流。

正在加载评论...