Codeforces Round 906

由于水平有限,只能打 div2。

当天时间没打完就睡了,白兰白兰。

A

观察到同奇偶的位置数必须相等,简单分讨即可。

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=2e5+60,M=2e6+20,mod=998244353;
int n,a[N],b[N];
void solve(){
	cin>>n;
	int tot=0;
	for(int i=1;i<=n;i++) cin>>a[i]; 
	sort(a+1,a+n+1);
	for(int i=1;i<n;i++) if(a[i]!=a[i+1]) tot++;
	if(tot<2){
		if(tot==0) return cout<<"Yes\n",void();
		int cnt=0; 
		for(int i=1;i<=n;i++){
			cnt+=(a[i]==a[1]);
		}
		if(cnt!=n/2&&cnt!=(n+1)/2) cout<<"No\n";
		else cout<<"Yes\n";
	}
	else cout<<"No\n";
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

B

如果 \(s,t\) 都不是好串显然无解,而如果 \(t\) 不是好串那么插入 \(t\) 显然没用,若 \(t\) 是好串而首尾不同也没用,所以唯一只用考虑 \(t\) 首尾相同,随便判判即可。

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=1e4+60,M=2e6+20,mod=998244353;
int n,m;char s[N],t[N];
void solve(){
	cin>>n>>m;
	cin>>s>>t;
	bool fl=1;
	int lst=-1;
	for(int i=0;i<n-1;i++){
		if(s[i]==s[i+1]){
			if(lst!=s[i]-'0'&&lst!=-1) return cout<<"No\n",void();
			lst=s[i]-'0';
		}
	}
	if(lst==-1) return cout<<"Yes\n",void();
	int can=-1;
	for(int i=0;i<m-1;i++){
		if(t[i]==t[i+1]) return cout<<"No\n",void();
	}
	if(t[0]==t[m-1]) can=t[0]-'0';
	else return cout<<"No\n",void();
	if(can!=lst) return cout<<"Yes\n",void();
	else return cout<<"No\n",void();
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

C

考虑无解的必要条件,若 \(0,1\) 个数都不一样显然无解。那么猜测 \(0,1\) 个数相同必然有解。

确实必然有解,考虑现在左右匹配的 \(0,1\) 直接删除,直到串最左右 为 \(0\ \text{or} \ 1\),考虑在左右加 \(01\) 必然有匹配掉一对然后某边多加 \(0\ \text{or} \ 1\)

例如 $0\dots 0 \rightarrow 100\dots 0 \rightarrow 00 \dots $ 即把其中右边的 \(0\) 扔到左边,\(1\) 同理会从左边扔到右边,固一直这样操作,最后一定变成 \(0\dots1\) 的形式,而又由于 \(0,1\) 个数相等,所以必然有解。

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
#define pb push_back
using namespace std;
const int N=1e4+60,M=2e6+20,mod=998244353;
int n;char s[N];
vector<int> ans;
void ins(int x){
	ans.pb(x);
	for(int i=n;i>x;i--) s[i+2]=s[i];
	s[x+1]='0';s[x+2]='1';n+=2;
//	cout<<s+1<<'\n'; 
}
int t[2];
void solve(){
	cin>>n;cin>>(s+1);
	ans.clear();
	t[0]=t[1]=0;
	for(int i=1;i<=n;i++) t[s[i]-'0']++;
	if(t[0]!=t[1]) return cout<<-1<<'\n',void();
	int l=1,r=n;
	while(l<r){
		if(s[l]!=s[r]) l++,r--;
		else if(s[l]=='0'){
			ins(r),l++,r++;
		}
		else ins(l-1),l++,r++;
	}
	cout<<(int)ans.size()<<'\n';
	for(int v:ans) cout<<v<<' ';cout<<'\n';
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

D

这题赛时李超树写到一半发现有更加简单做法(我就说大家为啥都做这么快)

首先一个显然的事情,如果 \(i,j(j<i)\) 连边了,那么 \(\forall k \in [1,i-1]\) 都会和 \(i\) 连边,因为 \(i\) 的连通块 \(a\) 的和加上 \(j\) 的连通块 \(a\) 的和 \(\geq i\times j \times c\),那么 \(i\) 连通块 \(a\) 的和变成上述两者相加,而 \(k\in[1,i-1]\)\(i\) 连边判断条件后者变小,前者变大显然满足。

那么考虑判断一个 \(i\) 前面时候存在 \(j<i\) 可以连向 \(i\),即 \(a_i+a_j \geq i \times j \times c\),通过移项 \(j(-ic)+a_j\geq -a_i\) 李超树维护即可,当然可以发现斜率上升,所以可以维护凸包栈,查询二分。

复杂度 \(O(n \log n)\)

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
#define int ll
using namespace std;
const int N=2e5+60,M=2e6+20,mod=998244353,Inf=1e18;
struct Node{int k,b;}s[N];
int stk[N],pos[N],tp,n,c,a[N],nxt[N];
inline int get(int i,int j){return (s[i].b-s[j].b)/(s[i].k-s[j].k)+1;}
void solve(){
	tp=0;cin>>n>>c;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) s[i].k=i,s[i].b=a[i]; 
	for(int i=1;i<=n;i++) nxt[i]=i+1;
	while(nxt[1]!=n+1){
		int i=1;bool fl=0;
		tp=0;
		for(;i<=n;i=nxt[i]){
			if(tp){
				int v=-i*c;
				int u=lower_bound(stk+1,stk+tp+1,v)-stk;
				if((__int128_t)v*s[stk[u]].k+s[stk[u]].b>=-a[i]){fl=1;break;}
			}
			while(tp&&get(stk[tp],i)<=pos[tp]) tp--;
			if(tp) pos[tp+1]=get(stk[tp],i);else pos[tp+1]=-Inf;
			stk[++tp]=i;
		}
		if(!fl) break; 
		for(int j=nxt[1];j<=i;j++){
			a[1]+=a[j];s[1].b+=a[j];
		}
		nxt[1]=i+1; 
	}
	if(nxt[1]==n+1) cout<<"Yes\n";
	else cout<<"No\n";
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T;cin>>T;s[0].b=-Inf;
	while(T--) solve();
	return 0;
}

E1/E2

先讲讲 E1,设 \(s_i\) 表示 \(i\) 这个位置被覆盖次数,首先考虑两种贡献,一种是两个区间无交,这种直接选择区间 \(s_i=1\) 个数最大值和次大值,如果选出的两个区间有交,会被有交算的答案覆盖,不优。

而不难发现,若一个点 \(s_i=2\) 则有一对区间有交,所以有交区间对数 \(O(n)\)

找出来暴力判断即可。

复杂度 \(O(n+m)\)

E2,\(k\) 变大了,考虑通过 dp 解决。

考虑一种容易想的暴力,枚举所有 选择没被覆盖的点集,判断删除覆盖这个点集的区间数是否 \(leq k\)

考虑怎么确定删除哪些区间的,考虑每个位置,考虑跨过上一个点的区间已经删除,设当前 \(i\)未被覆盖,上个未被覆盖位置为 \(j\),那么对于满足 \(j<l\leq i\leq r\)\([l,r]\) 需要删除。

那么就可以 dp了,\(f_{i,p}\) 表示考虑 \([1,i]\)\(i\) 未被覆盖,已经删除了 \(p\) 个区间,设 \(s_j=\sum\limits_{p=1}^{m} [j<l_p\leq i\leq r_p]\),有 \(f_{i,p} \leftarrow f_{j,p-s_j}\)

这样是 \(O(n^2k)\),考虑优化。

注意 \(s_j>k\) 的没有意义,而随着 \(j\) 的增大,\(s_j\) 减小,那么可以算出 \(k\) 个分界点,然后用 st 表维护查询,st 表顺序插入是 \(O(\log n)\) 的。

复杂度 \(O(n k^2+n \log n k)\)

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
#define pii pair<int,int>
#define MP make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
const int N=2e5+20,M=1e6+20,mod=998244353,LGN=20,Inf=1e9;
int lg[N];
struct ST{
	int a[N][LGN+2];
	inline void ins(int p,int v){
		a[p][0]=v;
		for(int i=1;i<LGN;i++) a[p][i]=max(a[p][i-1],a[max(0,p-(1<<i-1))][i-1]);
	}
	inline int qry(int l,int r){
		int k=lg[r-l+1];
		return max(a[r][k],a[l+(1<<k)-1][k]);
	}
}st[11];
int n,m,k,f[N][11],in[N];
vector<pii> s;
vector<int> out[N];
map<int,int> mp;
void solve(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++) in[i]=0,out[i].clear();
	for(int i=0;i<=n;i++) for(int j=0;j<=k;j++) f[i][j]=-Inf;
	f[0][0]=0;
	for(int i=1,l,r;i<=m;i++){
		cin>>l>>r;in[l]++,out[r].pb(l);
	}
	st[0].ins(0,0);
	for(int i=1;i<=n;i++){
		s.clear();
		mp[i]+=in[i];
		if(!mp[i]) mp.erase(i);
		auto p=mp.end();
		if(p==mp.begin()){
			for(int j=0;j<=k;j++) f[i][j]=st[j].qry(0,i-1)+1;
		}
		else{
			--p;int e=0;
			for(;e<=k;){
				if((*p).fi!=i) s.pb(MP((*p).fi,e));
				e+=(*p).se;
				if(p==mp.begin()) break;
				--p;
			}
			int lst=i-1;
			for(int q=0;q<(int)s.size();q++){
				pii u=s[q];
//				printf("%d %d %d\n",u.fi,i,u.se);
				for(int j=u.se;j<=k;j++) f[i][j]=max(f[i][j],st[j-u.se].qry(u.fi,lst)+1);
				lst=u.fi-1;
			}
			if(e<=k){
				for(int j=e;j<=k;j++) f[i][j]=max(f[i][j],st[j-e].qry(0,lst)+1);
			}
		}
		for(int j=0;j<=k;j++) st[j].ins(i,f[i][j]);
		for(int v:out[i]) if(!--mp[v]) mp.erase(v);
	}
	for(int i=0;i<=k;i++) for(int j=0;j<=n;j++) for(int p=0;p<LGN;p++) st[i].a[j][k]=0;
	int ans=0;
	for(int i=0;i<=n;i++) ans=max(ans,f[i][k]);
	cout<<ans<<'\n';
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	lg[0]=-1;for(int i=1;i<N;i++) lg[i]=lg[i>>1]+1;
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

F

sb 题,赛时没看。

首先考虑栈大小为 \(1\) 怎么做,连 \(i\rightarrow p_i\) 有环没用,会跑回自己。

所以删掉环,每个点的答案就是自己内向树的根。

多个点同理的,不断删环即可。

复杂度 \(O(n+ \sum k)\)

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=1e5+20,M=1e6+20,mod=998244353;
stack<int> s[N];
int n,ans[N],stk[N],tp;bool vis[N];
int dfs(int u){
	if(ans[u]) return ans[u];
	if(s[u].empty()) return u;
	if(vis[u]){
		stk[tp+1]=0;
		while(stk[tp+1]!=u){
			s[stk[tp]].pop();vis[stk[tp]]=0;tp--;
		}return dfs(u);
	}
	stk[++tp]=u;vis[u]=1;
	return dfs(s[u].top());
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1,k;i<=n;i++){
		cin>>k;
		for(int j=1,v;j<=k;j++) cin>>v,s[i].push(v);
	}
	for(int i=1;i<=n;i++){
		tp=0;int res=dfs(i);
		for(int j=1;j<=tp;j++) ans[stk[j]]=res;
		cout<<res<<' ';
	}
	return 0;
}
posted @ 2023-10-29 21:01  Detect-Perplexity  阅读(94)  评论(1编辑  收藏  举报