Codeforces Round 866 (Div. 2)

ZMY 是唯一的神迹

感觉整场偏简单

A. Yura's New Name

可以直接贪心的在每个后面不是^_后面加上一个^

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxN=2*1e5+10;

void solve(){
	string str;
	cin >> str;
	int sum=0;
	vector<int> v;
	for(int i=0;i<str.length() ;++i){
		if(str[i]=='^') v.push_back(i);
	}
	if(v.empty()){
		cout << str.length()+1 << endl;
		return;
	}
    if(v.size()==1&&str.length()==1) {
        cout << 1 << endl;
        return ;
    }
	for(int i=0;i<v.size()-1;++i){
		if(v[i]==v[i+1]-1) continue ;
		else sum+=(v[i+1]-v[i]-2);
	}
	int k=0;
	for(int i=0;i<str.length();++i){
		if(str[i]=='_'){
			++k;
		}
		else {
			break;
		}
	}
	sum+=k;
	k=0;
	for(int i=str.length()-1;i>=0;--i){
		if(str[i]=='_'){
			++k;
		}
		else {
			break;
		}
	}
	sum+=k;
	cout << sum << endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0); 
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	
	return 0;
} 

B. JoJo's Incredible Adventures

很明显,每一个矩形都对应着原序列中的一个全 1 段,循环会使头部的段和尾部的段拼接在一起

同时,每对一个已经拼好的矩形继续进行移动,并不会改变其的周长,我们为了使其的面积尽量大,需要让其接近一个正方形

代码删了一些头文件,有可能导致无法过编译

#include <cstdio>
using namespace std;
ll t, i, j, w, n, z = 0, maxx = 0;
char a[200010] = {};
int main() {
    scanf("%lld", &t);
    while (t--) {
        cin >> a;
        n = strlen(a) - 1;
        bool f = 0;
        z = 0;
        maxx = 0;
        w = 0;
        for (i = 0; i <= n; i++) {
            if (a[i] == '0' && f == 0) {
                f = 1;
                w = z;
            }
            if (a[i] == '0') {
                maxx = max(maxx, z);
                z = 0;
            }
            if (a[i] == '1') {
                z++;
            }
        }
        maxx = max(maxx, z + w);
        maxx++;
        if (f == 1)
            cout << maxx / 2 * (maxx / 2 + maxx % 2) << endl;
        else {
            cout << (maxx - 1)*(maxx - 1) << endl;
        }
    }
    return 0;
}

C. Constructive Problem

沙币题

但有个更沙币的废物因为读错了题导致没有切

很明显,我们要求使mex加一有两个条件

  1. 必须有的数要调整到mex
  2. 所有的等于mex+1的数都要被出去

那简单了,我们找出一个包含所有mex+1的数的区间,然后把所有的数都调整到mex,看看是否合法就可以了

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#define ll long long
#define reg register
#define fo(a,b,c) for(reg ll a=b;a<=c;a++)
#define re(a,b,c) for(reg ll a=b;a>=c;a--)
#define pii pair<ll,ll>
#define fi first
#define se second
#define mod 998244353
using namespace std;
inline ll gi(){
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
ll a[200005];
map<ll,ll> mp;
void sol()
{
	ll n=gi();
	mp.clear();
	ll l=0,r=0;
	fo(i,1,n)
	{
		a[i]=gi();
		mp[a[i]]++;
	}
	ll t=0;
	while(mp[t]) t++;
	ll z=t;
	fo(i,1,n)
	{
		if(a[i]==t+1)
		{
			if(l==0) l=i;
			r=i;
		}
	}
	fo(i,l,r)
	{
		a[i]=t;
	}
	mp.clear();
	if(l==r&&r==0)
	{
		if(t!=n)
		{
			cout<<"YES";
		}
		else cout<<"NO";
		return;
	}
	fo(i,1,n)
	{
		mp[a[i]]++;
	}
	t=0;
	while(mp[t]) t++;
	if(t==z+1) cout<<"YES";
	else cout<<"NO";
}
int main()
{
	ll _=gi();
	while(_--)
	{
		sol();
		cout<<'\n';
	}
	return 0;
}

D. The Butcher

这道题吧,其实我觉得真不难,但不知为何,场切的人比较少

首先一个明显的结论,我们这里只有两种构建方案

分别是将最长的h拿出来和把最长的w拿出来

接下来就枚举一遍所有子矩形,若有一条边能与目前的重合,那就证明其一定是和第一次切的是同一类的,我们把它加进去,然后算贡献算到另一维度头上去

接下来,我们在剩余的子矩形中选出一个另一维度最长的矩形,将其的另一维度加入贡献

接下来怎么判合法性呢,这里有一个假的要死的结论,如果这样构造出来的大矩形的面积等于所有子矩形的面积之和,就认为这样是合法的

不得不说 wzh 是真的敢想

这个假的要死的结论通过了system test,但立刻就被Hack

真正的结论是这样的,我们枚举一个维度,删掉所有与这个维度符合的子矩形,然后减去另一个的贡献,再换到另一个维度去枚举就可以了,等什么时候删掉了0,或者没有子矩形了,就退出,结算一下

具体实现中,使用了两个mulitset,一个以h为关键字,一个以w为关键字,以实现不同维度之间的交换

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ld long double
#define inf 0x7ffffff
#define pii pair<int,int>

using namespace std;
const int maxN=2*1e5+10;
int t,n;
int vis[maxN];
pii a[maxN];

bool check(int h,int w,int st){
	multiset<pii> s[2];
	int p[2];
	p[0]=h,p[1]=w;
	for(int i=1;i<=n;++i)
		s[0].insert(a[i]),s[1].insert({a[i].second,a[i].first});
	for(int i=st;p[1]&&p[0];i^=1){//i=0为h,i=1为w
		auto now=*s[i].rbegin();
		if(now.first!=p[i])
			return false;
		while(!s[i].empty()&&s[i].rbegin()->first==p[i]){
			auto x=*s[i].rbegin();
			s[i].erase(s[i].lower_bound(x));
			s[i^1].erase(s[i^1].lower_bound({x.second,x.first}));
			p[i^1]-=x.second;
			if(p[i^1]<0) 
				return false;
		}
		if(s[i].empty()){
			if(p[i^1]!=0)
				return false;
			else return true;
		}
	}
	if(!s[0].empty()){
		return false;
	}
	return true;
}

void solve(){
	cin >> n;
	int maxh=0,maxw=0,sum=0;
	for(int i=1;i<=n;++i){
		cin >> a[i].first >> a[i].second;
		maxh=max(maxh,a[i].first),maxw=max(maxw,a[i].second);
	}
	int h=maxh,w=0;
	for(int i=1;i<=n;++i)
		if(a[i].first==h) w+=a[i].second,vis[i]=1;
	int temp=0;
	for(int i=1;i<=n;++i){
		if(vis[i]) continue ;
		temp=max(temp,a[i].second);
	}
	w+=temp;
	vector<pii> ans;
	if(check(h,w,0))++sum,ans.push_back({h,w});
	w=maxw,h=0;
	for(int i=1;i<=n;++i) vis[i]=0;
	for(int i=1;i<=n;++i)
		if(a[i].second==w) h+=a[i].first,vis[i]=1;
	temp=0;
	for(int i=1;i<=n;++i){
		if(vis[i]) continue ;
		temp=max(temp,a[i].first);
	}
	for(int i=1;i<=n;++i) vis[i]=0;
	h+=temp;
	if(check(h,w,1))++sum,ans.push_back({h,w});
	if(sum==2&&ans[0]==ans[1]) ans.pop_back(),sum--;; 
	cout << sum << endl;
	for(pii x:ans)
		cout << x.first << " " << x.second << endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0); 
	cin >> t ;
	while(t--){
		solve();
	}
	return 0;
} 

E. The Fox and the Complete Tree Traversal

不错的构造

这个条件非常明显,我们可以让一个节点跳到与其距离为 1 的节点上去,同时,我们有一个奇妙的发现:

画红圈的这些节点可以相互跳到,这个形式给了我们启发

这里我也不知道怎么过渡了,直接放结论,一颗树有解的充要条件是其删去所有叶子结点之后的节点是一条链

首先,我们来证明其如果有一个三叉的情况,就一定无解


如图所示,显而易见,我们从A开始跳,第一次不能经过中心节点,就要跳到 B 上,当我们跳入 B 的子树的时候,若要再次跳出来,就一定要经过中心节点,明显不符合条件

同时,我们发现,可以通过下面的方法来构造一组答案

这里上面的节点代表了其挂住的叶结点,由于其叶结点之间是可以相互跳的,所以只用一个节点代替

好的,问题到了这里,就变为了,怎么找出这条路径

我们发现,这条路径一定是整颗无根树的直径,因为如果存在这样的路径,则整颗树可以想象为一个路径上长出了一圈的节点,则我们找出直径,进行构造就可以了

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ld long double
#define inf 0x7ffffff

using namespace std;
const int maxN=2*1e5+10;
int n,c,w,flag,flag2;
int dep[maxN],siz[maxN];
vector<int>g[maxN],path,leaf[maxN];

void dfs(int now,int f,int &p){
	dep[now]=dep[f]+1,siz[now]=1;
	if(dep[now]>dep[p]) p=now;
	int tot=0;
	for(int x:g[now]){
		if(x==f) continue ;
		dfs(x,now,p);
		siz[now]+=siz[x];
		if(siz[x]>1) ++tot;
		if(!path.empty()){
			if(tot>1)flag=1;
			if(siz[x]==1) leaf[now].push_back(x);
		}
	}
}

void dfs2(int now,int f){
	path.push_back(now);
	for(int x:g[now]){
		if(x==f) continue ;
		if(x==w){
			flag2=1;
			return ;
		}
		dfs2(x,now);
		if(flag2) return ;
		
	}
	if(flag2) return ;
	path.pop_back();
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0); 
	cin >> n;
	for(int i=1;i<n;++i){
		int u,v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,1,c);
	memset(dep,0,sizeof(dep));
	memset(siz,0,sizeof(siz));
	dfs2(c,c);
	int temp;
	dfs(c,c,temp);
	if(flag==1){
		cout << "No" << endl;
		return 0;
	}
	
	cout <<  "Yes" << endl;
	int sy=1;//1为选,0为不选
	for(int i=0;i<path.size();++i){
		if(sy) cout << path[i] << " ";
		else for(int x:leaf[path[i]])
				cout << x << " ";
		sy^=1;
	}
	for(int i=path.size()-1;i>=0;--i){
		if(sy) cout << path[i] << " ";
		else for(int x:leaf[path[i]])
			cout << x << " ";
		sy^=1;
	}cout << endl;
	
	return 0;
} 
posted @ 2023-04-15 22:54  颈流推进  阅读(56)  评论(0)    收藏  举报