pyyzDay14

模拟赛(不错?)

T1 Segments Removal

双向链表考虑合并

注意到堆中记录区间长度和id

一个升序一个降序不好维护

于是倒序输入

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[200005],pre[200005],nxt[200005],col[200005],siz[200005],cnt,vis[200005];
priority_queue<pair<int,int> > hp;
signed main() {
	//	freopen("remove.in","r",stdin);
	//	freopen("remove.out","w",stdout);
	int n;
	cin>>n;
	for(int i=n;i;i--) cin>>a[i];
	for(int i=1;i<=n;i++){
		if(a[i]==a[i-1]) siz[cnt]++;
		else{
			col[++cnt]=a[i];
			siz[cnt]=1;
		}
	}
	for(int i=1;i<=cnt;i++){
		pre[i]=i-1;
		nxt[i]=i+1;
		hp.push({siz[i],i});
	}
	int ans=0;
	while(!hp.empty()){
		int c=hp.top().second;
		hp.pop();
		if(vis[c]) continue;
		ans++;
		int l=pre[c],r=nxt[c];
		pre[r]=l;
		nxt[l]=r;
		vis[c]=1;
		if(col[l]==col[r]&&r<=n&&l>=1){
			nxt[pre[l]]=r;
			pre[r]=pre[l];
			vis[l]=1;
			siz[r]+=siz[l];
			hp.push({siz[r],r});
		}
	}
	cout<<ans<<'\n';
	return 0;
}

T2 [USACO23OPEN] FEB B

赛时切!

大分讨(对着暴力猜结论)

找F连续段,分长度奇偶/两端是否相等分别计算即可

发现答案是公差为1/2的等差数列

计算出首项min末项max就知道了整个数列

#include<bits/stdc++.h>
using namespace std;
#define int long long
set<int> ans;
string s;
int n;
int l[20];
void dfs(int x){
	if(x==n){
		int sum=0;
		string q=s;
		for(int i=1;i<=n;i++){
			if(l[i]&&q[i-1]=='F') q[i-1]='E';
			else if(!l[i]&&q[i-1]=='F') q[i-1]='B';
		}
		for(int i=0;i<n;i++){
			if(q[i]==q[i+1]) sum++;
		}
		ans.insert(sum);
		return ;
	}
	x++;
	dfs(x);
	l[x]=1;
	dfs(x);
	l[x]=0;
} 
signed main() {
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);
	cin>>n;
	cin>>s;
	if(n<=10){
		dfs(0);
		cout<<ans.size()<<'\n';
		for(auto ed:ans){
			cout<<ed<<'\n';
		}
		return 0;
	}
	int an=0;
	for(int i=1;i<n-1;i++){
		if(s[i]=='F'&&s[i-1]=='B'&&s[i+1]=='E') s[i]='B';
		else if(s[i]=='F'&&s[i+1]=='B'&&s[i-1]=='E') s[i]='B';
		else if(s[i]=='F'&&s[i-1]!='F'&&s[i+1]!='F') an++;
	}
	int len=0,minn=0,anss=0;
	for(int i=0;i<n;i++){
		if(s[i]=='F'&&s[i+1]=='F'){
			int j=i+1;
			int ll=1;
			while(s[j]=='F'&&j<n){
				j++;
				ll++;
			}
			if(!i||j>=n||s[i-1]!=s[j]){
				if(!i&&j>=n) ll--;
				if(i&&j<n&&ll%2==1) minn++;
			}
			else{
				if(ll%2==0) minn++;
				ll++;
			}
			i=j;
			len+=ll;
		}
	}
	for(int i=0;i<n;i++){
		if(s[i]==s[i+1]&&s[i]!='F') anss++;
	}
	int st=anss+minn,en=anss+len+2*an;
	if(s[0]=='F'||s[n-1]=='F'){
		if(s[0]=='F'&&s[1]!='F') en++;
		if(s[n-1]=='F'&&s[n-2]!='F') en++;
		cout<<en-st+1<<'\n';
		for(int i=st;i<=en;i++) cout<<i<<'\n';
	}
	else{
		cout<<(en-st)/2+1<<'\n';
		for(int i=st;i<=en;i+=2) cout<<i<<'\n';
	}
	return 0;
}

T3 [SDOI2016] 齿轮

大法师!

数据范围较小

对每个点进行图遍历

看是否会卡住

注意除法精度问题(不要像我一样赛时不开double)

#include<bits/stdc++.h>
using namespace std;
const long double eps=1e-10;
vector<pair<int,pair<long double,long double> > > tu[1005];
int n,m,ff,vis[1005];
long double lin[1005];
void dfs(int x,long double sum){
	if(vis[x]){
		if(fabs(lin[x]-sum)>eps) ff=1;
		return ;
	}
	vis[x]=1;
	lin[x]=sum;
	for(auto ed:tu[x]){
		long double gx=ed.second.first;
		long double gy=ed.second.second;
		dfs(ed.first,sum*gx/gy);
	}
} 
void solve(int bianhao){
	memset(lin,0,sizeof(lin));
	memset(vis,0,sizeof(vis));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		tu[i].clear();
	}
	for(int i=1;i<=m;i++){
		int l,r;
		long double x,y;
		cin>>l>>r>>x>>y;
		tu[l].push_back({r,{x,y}});
		tu[r].push_back({l,{y,x}});
	}
	ff=0;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			dfs(i,1.0);
		}  
		if(ff) break;
	}
	if(ff) cout<<"Case #"<<bianhao<<": No"<<'\n'; 
	else cout<<"Case #"<<bianhao<<": Yes"<<'\n'; 
}
signed main() {
	//freopen("gear.in","r",stdin);
	//freopen("gear.out","w",stdout);
	int T;
	cin>>T;
	for(int i=1;i<=T;i++){
		solve(i);
	}
	return 0;
}

也可记录每个x,y,约分,防止失精

#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<pair<int,pair<int,int> > > tu[1005];
int n,m,ff,vis[1005],suma[1005],sumb[1005];
void dfs(int x,int sua,int sub){
	if(vis[x]){
		if(suma[x]*sub!=sumb[x]*sua) ff=1;
		return ;
	}
	vis[x]=1;
	suma[x]=sua;
	sumb[x]=sub;
	int gg=__gcd(abs(suma[x]),abs(sumb[x]));
	suma[x]/=gg;
	sumb[x]/=gg;
	for(auto ed:tu[x]){
		int gx=ed.second.first;
		int gy=ed.second.second;
		gx*=sua;
		gy*=sub;
		int g=__gcd(abs(gx),abs(gy));
		gx/=g;
		gy/=g;
		dfs(ed.first,gx,gy);
		if(ff) return ;
	}
} 
void solve(int bianhao){
	memset(suma,0,sizeof(suma));
	memset(sumb,0,sizeof(sumb));
	memset(vis,0,sizeof(vis));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		tu[i].clear();
	}
	for(int i=1;i<=m;i++){
		int l,r;
		int x,y;
		cin>>l>>r>>x>>y;
		tu[l].push_back({r,{x,y}});
		tu[r].push_back({l,{y,x}});
	}
	ff=0;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			dfs(i,1,1);
		}  
		if(ff) break;
	}
	if(ff) cout<<"Case #"<<bianhao<<": No"<<'\n'; 
	else cout<<"Case #"<<bianhao<<": Yes"<<'\n'; 
}
signed main() {
	//freopen("gear.in","r",stdin);
	//freopen("gear.out","w",stdout);
	int T;
	cin>>T;
	for(int i=1;i<=T;i++){
		solve(i);
	}
	return 0;
}

T4 [POI 2010] GRA-The Minima Game

博弈论DP

发现每个数的顺序和个数不重要

排序去重

设dp_i表示考虑1~i先手的最大优势

考虑枚举j,表示一次拿走j+1~i

则dp_i=max(dp_i,a_(j+1)-dp_j)

发现dp_i在不断更新

dp_i存储i以前的最大的a_(j+1)-dp_j

所以转移方程只需O(n)枚举i

dp_i=max(dp_(i-1),a_i-dp_(i-1))

即只考虑是否只选i

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[1000005],dp[1000005];
signed main() {
	//	freopen("game.in","r",stdin);
	//	freopen("game.out","w",stdout);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	int len=unique(a+1,a+n+1)-a-1;
	for(int i=1;i<=len;i++){
		dp[i]=max(dp[i-1],a[i]-dp[i-1]);
	} 
	cout<<dp[len]<<'\n';
	return 0;
}
posted @ 2025-08-19 16:22  gbrrain  阅读(5)  评论(0)    收藏  举报