Codeforces Round #669 (Div. 2) 题解 (ABC)

最近有点忙,这场就写到C吧,D我口胡一下(懒得补)

A. Ahahahahahahahaha

题目读错了,没看到 \(n\) 是偶数(藏在这么隐蔽的地方),题目就复杂好多但是居然有解

先说正解,因为只有偶数,如果1的个数小于等于 \(\dfrac n 2\),就删掉所有的1,否则删掉所有0,并且在1的个数是奇数的时候删掉一个1

(然后讲一下新题目,不看也罢)n不一定是偶数。找到连续的两个1或者连续的两个0,无视它们就不会对结果产生影响。删掉它们后(并不是真的删掉因为最后还是要输出的),序列只可能是0101..或者1010..(0和1交替出现)。对于0101..,删掉所有的1就行了。对于1010..,我们删掉第一个0和第3个以及之后所有的1,变成11000..,这样删掉的数量不超过n/2。还有一个特殊情况10,要删掉第一个1

为什么A题能被我想得这么复杂,实属迷惑行为

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
typedef long long ll; typedef double lf; typedef pair<ll,ll> pii;
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0); ll read(); lf readf();
const int inf=~0u>>2; const ll INF=~0ull>>2; const lf pi=acos(-1.0);
template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
const int N=200010; const ll mod=(1?1000000007:998244353); ll mul(ll,ll,ll); ll qpow(ll,ll,ll);
#define int ll
vector<int> stk;
int a[N],ans[N];
void Solve(){
	int n=read(); stk.clear();
	repeat(i,0,n){
		a[i]=read(); stk<<i; //"<<" means push_back
		if(stk.size()>=2 && a[stk.rbegin()[0]]==a[stk.rbegin()[1]])
			stk.pop_back(),stk.pop_back();
	}
	fill(ans,ans+n,1);
	if(stk.size()==2)
		for(auto i:stk)ans[i]=!a[i];
	else if(stk.size()>=2)ans[stk[1]]=0;
	repeat(i,3,stk.size())if(a[stk[i]])ans[stk[i]]=0;
	cout<<accumulate(ans,ans+n,0)<<endl;
	repeat(i,0,n)if(ans[i])cout<<a[i]<<' ';
	cout<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}
ll read(){
	ll x; if(scanf("%lld",&x)==-1)exit(0);
	return x;
}
lf readf(){
	lf x; if(scanf("%lf",&x)==-1)exit(0);
	return x;
}
ll mul(ll a,ll b,ll m=mod){
	return a*b%m;
}
ll qpow(ll a,ll b,ll m=mod){
	ll ans=1;
	for(;b;a=mul(a,a,m),b>>=1)
		if(b&1)ans=mul(ans,a,m);
	return ans;
}

B. Big Vova

第一个数显然是原序列的最大值。如果处理出了前i个数,我们计算前i个数的gcd为d,找到剩下的数里gcd(d,a[i])最大的a[i]作为第i+1个数即可

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
typedef long long ll; typedef double lf; typedef pair<ll,ll> pii;
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0); ll read(); lf readf();
const int inf=~0u>>2; const ll INF=~0ull>>2; const lf pi=acos(-1.0);
template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
const int N=200010; const ll mod=(1?1000000007:998244353); ll mul(ll,ll,ll); ll qpow(ll,ll,ll);
#define int ll
vector<int> a,ans;
void Solve(){
	int n=read(); a.clear(); ans.clear();
	repeat(i,0,n)a<<read();
	int now=*max_element(a.begin(),a.end());
	repeat(i,0,n){
		int p=max_element(a.begin(),a.end(),[&](int x,int y){
			return __gcd(now,x)<__gcd(now,y);
		})-a.begin();
		now=__gcd(now,a[p]);
		ans<<a[p];
		swap(a[p],a.back());
		a.pop_back();
	}
	for(auto i:ans)cout<<i<<' ';
	cout<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}
ll read(){
	ll x; if(scanf("%lld",&x)==-1)exit(0);
	return x;
}
lf readf(){
	lf x; if(scanf("%lf",&x)==-1)exit(0);
	return x;
}
ll mul(ll a,ll b,ll m=mod){
	return a*b%m;
}
ll qpow(ll a,ll b,ll m=mod){
	ll ans=1;
	for(;b;a=mul(a,a,m),b>>=1)
		if(b&1)ans=mul(ans,a,m);
	return ans;
}

C. Chocolate Bunny

因为模的运算很头疼,但是一个非常有用的性质直接能秒掉这题。如果有两个数a,b(a≠b),如果a%b>b%a,那么a的值就是a%b,否则b的值是b%a

上述操作可以消耗两次询问直接确定一个数的值。我们每次拿出两个未知的位置进行两次询问,也就是说每次都有一个未知的数变成已知的数。只要2(n-1)次询问后即可确定n-1个数,最后那个数就不用说了

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
typedef long long ll; typedef double lf; typedef pair<ll,ll> pii;
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0); ll read(); lf readf();
const int inf=~0u>>2; const ll INF=~0ull>>2; const lf pi=acos(-1.0);
template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
const int N=200010; const ll mod=(1?1000000007:998244353); ll mul(ll,ll,ll); ll qpow(ll,ll,ll);
#define int ll
int ans[N];
int query(int x,int y){
	cout<<"? "<<x<<' '<<y<<endl; cout.flush();
	int a; cin>>a;
	cout<<"? "<<y<<' '<<x<<endl; cout.flush();
	int b; cin>>b;
	if(a>b){ans[x]=a; return y;}
	else {ans[y]=b; return x;}
} 
void Solve(){
	int n; cin>>n;
	int p=1;
	repeat(i,2,n+1)
		p=query(p,i);
	cout<<"! ";
	repeat(i,1,n+1){
		if(ans[i]==0)ans[i]=n;
		cout<<ans[i]<<' ';
	}
	cout<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}
ll read(){
	ll x; if(scanf("%lld",&x)==-1)exit(0);
	return x;
}
lf readf(){
	lf x; if(scanf("%lf",&x)==-1)exit(0);
	return x;
}
ll mul(ll a,ll b,ll m=mod){
	return a*b%m;
}
ll qpow(ll a,ll b,ll m=mod){
	ll ans=1;
	for(;b;a=mul(a,a,m),b>>=1)
		if(b&1)ans=mul(ans,a,m);
	return ans;
}

D题,这个性质很容易(并不)想到单调栈。单调栈弹出的数和当前正在访问的数就刚好可以构成题目中的规则2或者规则3(取决于单增的单调栈还是单减的单调栈)

posted @ 2020-09-09 14:09  axiomofchoice  阅读(168)  评论(0编辑  收藏  举报