Codeforces 1710 A,B,C,E

A,C做时没有遇到太多困难,所以这里就略写。
既然E是一个Well-Known Problem,那么也写一下E的题解吧。

A
容易发现最终一定是若干行组成的一个条状的东西,这样之间暴力即可。

B
首先观察到积水量最大的点一定是某次降雨的中心。
第一个问题就是我们如何求出所有降雨中心的积水量。

区间加同一个数,我们可以想到差分。
那么区间加1,2,...,n,n1,...,1呢?使用二维差分。

具体的,对于一次降雨xi,pi,那么二维差分数组ch[xipi]:=ch[xipi]+1,ch[xi]:=ch[xi]2,ch[xi+pi]:=ch[xi+p+i]+1

对二维差分进行一次前缀和,就可以得到一维差分;再进行一次前缀和,就可以得到各个点的降雨量。

对于坐标负数,这个很好解决——使用map存储差分数组;但是我们发现,二维差分点数是O(n)的,但是对二维差分做两次前缀和后,这个数组的长度会很大,所以要想得到原先点的降雨量,不能暴力做。我们可以之间用二维差分数组直接得到各个点的降雨量,具体的,如果我们要计算Pos点的降雨量,那么我们找到所有<Pos的差分数组(i,ch(i)),其贡献是(Posi)×ch(i)。所以我们就可以直接写出下面的程序:

scanf("%d%lld",&n,&m);
std::map<ll,ll> ch;
std::vector<ll> pos,val;
for(int i=1;i<=n;i++) {
	scanf("%lld%lld",&x[i],&p[i]);
	ch[x[i]-p[i]]++;
	ch[x[i]]-=2;
	ch[x[i]+p[i]]++;
	pos.push_back(x[i]);
	id[i]=i;
}
std::sort(pos.begin(),pos.end());
pos.erase(std::unique(pos.begin(),pos.end()),pos.end());
std::map<ll,ll>::iterator it=ch.begin();
ll sum=0,now=0;
for(int i=0;i<(int)pos.size();i++) {
	if(i) sum+=(pos[i]-pos[i-1])*now;		
	while(it!=ch.end()&&it->first<pos[i]) {
		now+=it->second;
		sum+=(pos[i]-it->first)*(it->second);
		it++;
	}
	val.push_back(sum);
}

于是我们得到每个降雨中心的位置pos(i)和对应的积水量val(i)。如果我们撤销第j次降水,那么必须满足对于所有val(i)>mi

  1. pos(i)xj,则val(i)(pj(xjpos(i)))必须小于等于m
  2. pos(i)>xj,则val(i)(pj(pos(i)xj))必须小于等于m
    化简这两个式子:

val(i)(pj(xjpos(i)))mval(i)(pjxj+pos(i))mval(i)pj+xjpos(i)mxjpjmval(i)+pos(i)val(i)(pj(pos(i)xj))mval(i)(pjpos(i)+xj)mval(i)pj+pos(i)xjmpjxjmval(i)pos(i)

这可以用两个set存储。

具体程序见:

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

using ll=long long;
const int maxn=200005;
int n;
ll m,x[maxn],p[maxn],id[maxn],ans[maxn];

bool cmp(int id1,int id2) {
	return x[id1]<x[id2];
} 

void solve() {
	scanf("%d%lld",&n,&m);
	std::map<ll,ll> ch;
	std::vector<ll> pos,val;
	for(int i=1;i<=n;i++) {
		scanf("%lld%lld",&x[i],&p[i]);
		ch[x[i]-p[i]]++;
		ch[x[i]]-=2;
		ch[x[i]+p[i]]++;
		pos.push_back(x[i]);
		id[i]=i;
	}
	std::sort(pos.begin(),pos.end());
	pos.erase(std::unique(pos.begin(),pos.end()),pos.end());
	std::map<ll,ll>::iterator it=ch.begin();
	ll sum=0,now=0;
	for(int i=0;i<(int)pos.size();i++) {
		if(i) sum+=(pos[i]-pos[i-1])*now;		
		while(it!=ch.end()&&it->first<pos[i]) {
			now+=it->second;
			sum+=(pos[i]-it->first)*(it->second);
			it++;
		}
		val.push_back(sum);
	}
	std::sort(id+1,id+n+1,cmp);
	std::multiset<ll> S,T;
	for(int i=0;i<(int)pos.size();i++) {
		if(val[i]>m) S.insert(val[i]-m+pos[i]);
	}
	for(int i=1,j=0;i<=n;i++) {
		while(j<(int)pos.size()&&pos[j]<=x[id[i]]) {
			if(val[j]>m) {
				S.erase(S.find(val[j]-m+pos[j]));
				T.insert(val[j]-m-pos[j]);	
			}
			j++;
		}
		bool r1=S.empty()||*S.rbegin()<=p[id[i]]+x[id[i]];
		bool r2=T.empty()||*T.rbegin()<=p[id[i]]-x[id[i]];
		if(r1&&r2) {
			ans[id[i]]=1;
		} else {
			ans[id[i]]=0;
		}
	}
	for(int i=1;i<=n;i++) putchar(ans[i]+'0');
	putchar('\n');
}

int main() {
	int T; scanf("%d",&T);
	while(T--) solve();
	return 0;
} 

C
一道比较板子的数位DP。设dp(i,s1,s2,s3,t1,t2,t3)表示考虑了a,b,c的前i位,在只考虑前i位的情况下,a,b,cn的大小关系为s1,s2,s3ab+bcacab+acbcac+bcab的大小关系为t1,t2,t3,此时合法的方案数。

转移也是比较简单的。

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

using ll=long long;
const ll mod=998244353;

int n;
std::string str;
ll f[200005][2][2][2][2][2][2];

#define REP(i,x,y) for(int (i)=(x);(i)<(y);(i)++)

int main() {
	std::cin>>str;
	std::reverse(str.begin(),str.end());
	n=str.size();
	str=" "+str;
	REP(a,0,2) REP(b,0,2) REP(c,0,2) {
		int dig=str[1]-'0';
		int s1=a>dig,s2=b>dig,s3=c>dig;
		int x=a^b,y=b^c,z=a^c;	
		int t1=x+y>z,t2=x+z>y,t3=y+z>x;			
		f[1][s1][s2][s3][t1][t2][t3]++;	
	}
	REP(i,1,n) REP(s1,0,2) REP(s2,0,2) REP(s3,0,2) REP(t1,0,2) REP(t2,0,2) REP(t3,0,2) {		
		REP(a,0,2) REP(b,0,2) REP(c,0,2) {			
			int i_=i+1;
			int dig=str[i+1]-'0';
			int s1_=(dig==a?s1:(dig<a?1:0));
			int s2_=(dig==b?s2:(dig<b?1:0));
			int s3_=(dig==c?s3:(dig<c?1:0));
			int x=a^b,y=b^c,z=a^c;
			int t1_=(z==x+y?t1:(z<x+y?1:0));
			int t2_=(y==x+z?t2:(y<x+z?1:0));
			int t3_=(x==y+z?t3:(x<y+z?1:0));
			f[i+1][s1_][s2_][s3_][t1_][t2_][t3_]+=f[i][s1][s2][s3][t1][t2][t3];
			f[i+1][s1_][s2_][s3_][t1_][t2_][t3_]%=mod;
		}
	}
	printf("%lld\n",f[n][0][0][0][1][1][1]);
	return 0;
}
posted @   Nastia  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示