CF1710 题解

比赛链接:https://codeforces.com/contest/1711
BD比以往的要难,E要更简单

A
水题

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

signed main(){
	int te;scanf("%d",&te);
	while(te --){
		int n;scanf("%d",&n);
		for(int i=1;i<=n;i++)printf("%d ", i == 1? n : i-1);
		puts("");
	}

	return 0;
}

B
如果一共有偶数对的话,显然全邀请最优
否则有奇数对,考虑某一对 \((a,b)\),显然如果 \(a\) 或者 \(b\) 在配对中出现了奇数次,就不邀请这个人,首先肯定满足偶数对条件,其次用这个人的 \(a\) 来更新答案,如果二者都出现了偶数次,那么同时删去 \(a\)\(b\) 的话,最后还是偶数对(ab重复了一次),更新答案

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e5+5;

int n,m;
int a[maxn], vis[maxn];
pii fr[maxn];

void solve(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]), vis[i] = 0;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&fr[i].first,&fr[i].second);
		++ vis[fr[i].first]; ++ vis[fr[i].second];
	}
	int res = 0;
	for(int i=1;i<=n;i++)if(!vis[i])res += a[i];
	if(m%2 == 0){
		puts("0");
		return ;
	}
	int r = 1e9;
	for(int i=1;i<=m;i++){
		int c = 0;
		int u=fr[i].first,v=fr[i].second;
		if(vis[u]&1)r=min(r,a[u]);
		if(vis[v]&1)r=min(r,a[v]);
		if(vis[u]%2==0&&vis[v]%2==0)r=min(r,a[u]+a[v]);
	}
	printf("%d\n",r);
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

C
行列同理,先讨论行
显然只能一整行一整行的画,而且相同颜色的行至少有两行
因此我们考虑一下统计能画超过2行的颜料数量,然后判一下能否画完就行了
有个反例:如果有5行,所有颜料都只能画2行,这样也是不行的。因此再判一下有没有能画超过2行的就行了

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e5 + 5;

int n,m,k;
int a[maxn], b[maxn], c[maxn];

void solve(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=k;i++)scanf("%d",&a[i]), b[i] = a[i] / n, c[i] = a[i] / m;
//	if(n%2==1 && m%2==1){
//		puts("NO");return ;
//	}
	LL fg1=0, fg2=0, fg3=0, fg4=0, fg01=0, fg03=0;
	for(int i=1;i<=k;i++){
		if(b[i] >= 2){
			fg1 += b[i];
			++ fg01;
			if(b[i] > 2)++ fg2;
		}
		if(c[i] >= 2){
			fg3 += c[i];
			++ fg03;
			if(c[i] > 2)++ fg4;
		}
	}
	if(m%2 == 0){
		if(fg1>=m){puts("Yes");return ;} 
	}else{
		if(fg1>=m && fg2){puts("Yes");return ;}
	}
	
	if(n%2 == 0){
		if(fg3>=n){puts("Yes");return ;}
	}else{
		if(fg3>=n && fg4){puts("Yes");return ;}
	}
	puts("No");
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

D
转化的比较神仙。
详见https://www.luogu.com.cn/problem/solution/CF1710B
大体思路就是将原来的降水和枚举删去哪一天降水分开,然后转化了一波模型变成了原来的降水能不能包含在 m + 枚举的降水 这个平面内
然后再转化,考虑原来的降水能被包含在哪些平面里面,发现相当于一个平面求交,所有的斜率都是 +1 -1,因此可以用截距表示(b0 b1)
最后判断是否在平面内的时候也可以用截距

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
#define int LL

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

map<int,int>mp;
int n,m,x[200005],p[200005];

void solve(){
	cin>>n>>m;
	mp.clear();
	for(int i=1;i<=n;i++){
		cin>>x[i]>>p[i];
		mp[x[i]-p[i]]++;
		mp[x[i]]-=2;
		mp[x[i]+p[i]]++;
	}
	int k=0, lst=-inf, cur=0;
	int b0=-inf, b1=-inf;
	for(auto it : mp){
		cur += k * (it.first - lst);
		k += it.second;
		
		if(cur > m){
			b0=max(b0,it.first+cur);
			b1=max(b1,cur-it.first);
		}
		
		lst = it.first;
	}
	for(int i=1;i<=n;i++){
		if(p[i]+m-x[i] >= b1 && p[i]+m+x[i] >= b0)
			cout<<1;
		else cout<<0;
	}
	puts("");
}

signed main(){
	int te;cin>>te;
	while(te--)solve();

	return 0;
}

E
数位dp傻逼题
比如考虑\(b \ xor\ a + b \ xor\ c > a \ xor\ c\)这个式子该如何满足,将abc赋值0/1打表发现只有2种情况,因此可以在状态中加一个0/1表示是否已经满足了,因为如果当前位满足了,剩下的位无论如何也一定满足题目条件
一遍写完过编译过样例AC好爽

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5 + 5, mod = 998244353;

char s[maxn];
int n;
int dp[maxn][2][2][2][2][2][2];	  // 考虑到第 i 位,abc与上界关系,三个限制是否满足

void add(int &x,int y){(x+=y)%=mod;}

int dfs(int x,int t1,int t2,int t3,int lim0,int lim1,int lim2){
	int &dd = dp[x][t1][t2][t3][lim0][lim1][lim2];
	if(x == n+1){
		if(t1+t2+t3 == 3)
			return dd = 1;
		else return dd = 0;
	}
	if(~dd)return dd;
	int up0 = lim0 ? s[x] - '0' : 1;
	int up1 = lim1 ? s[x] - '0' : 1;
	int up2 = lim2 ? s[x] - '0' : 1;
	int cur = 0;
#define limit lim0&&a==up0,lim1&&b==up1,lim2&&c==up2
	for(int a=0;a<=up0;a++){
		for(int b=0;b<=up1;b++)
			for(int c=0;c<=up2;c++){	
				if(b==1&&a+c==0)add(cur, dfs(x+1,t1,1,t3,limit));
				else if(b==0&&a+c==2)add(cur, dfs(x+1,t1,1,t3,limit));
				else{
					if(a==0&&b+c==2)add(cur, dfs(x+1,1,t2,t3,limit));
					else if(a==1&&b+c==0)add(cur, dfs(x+1,1,t2,t3,limit));
					else{
						if(c==1&&a+b==0)add(cur, dfs(x+1,t1,t2,1,limit));
						else if(a+b==2&&c==0)add(cur, dfs(x+1,t1,t2,1,limit));
						else add(cur,dfs(x+1,t1,t2,t3,limit));
					}
				}
			}
	}
	return dd = cur;
}

signed main(){
	memset(dp,-1, sizeof dp);
	scanf("%s",s + 1);
	n = strlen(s + 1);
	
	int ans = dfs(1,0,0,0,1,1,1);
	printf("%d\n",ans);

	return 0;
}
posted @ 2022-12-03 14:41  SkyRainWind  阅读(35)  评论(0编辑  收藏  举报