895 DIV3 [A~F]

发布时间 2023-09-08 01:10:12作者: 橘赴亦梦人ω

895 DIV3

A.

void solve()
{
	int a,b,c;
	cin>>a>>b>>c;
	int t=abs(a-b);
 
	double tt=t*1.0/2.0/c;
	
	t=tt;
	if(t<tt) t++;
	 cout<<t<<"\n";
 
}

B:

void solve()
{
	int n;
	cin>>n;
	int maxa=500;
	for(int i=1;i<=n;i++){
		int d,s;
		cin>>d>>s;
		s--;
		maxa=min(maxa,d+(s/2));
	}
	cout<<maxa<<"\n";
 
}

C:

  • 是一个元素且为质数,一定不行。
  • 其他情况里面只有最大元素<4不行。找一个偶数输出一半一半即可。
void solve()
{
	int a,b;
	cin>>a>>b;
	if(a==b){
		int k=-1;
		for(int i=2;i<=sqrt(a);i++){
			if(a%i==0){
				k=i; break;
			}
		}
		if(k==-1){
			cout<<"-1\n"; return ;
		}
		int num=a/k;
		int ans1=num; int ans2=a-ans1;
		cout<<ans1<<" "<<ans2<<"\n";
	}
	else{
		if(b<4){
			cout<<"-1\n"; return ;
		}
		if(b%2==1) b--;
		cout<<b/2<<" "<<b/2<<"\n";
	}
 
}

D:

  • 两者可能有重合的部分。预处理出来各自独立的部分有多少。
  • 然后x里面全部放最大的,另外一个全部放最小的。
void solve()
{
	int n,x,y;
	cin>>n>>x>>y;
	int p=x*y/gcd(x,y);
	int ans1=n/x;
	int ans2=n/y;
	int num=n/p;
	ans1-=num;
	ans2-=num;
	int sum=0;
	sum+=ans1*(n+n-ans1+1)/2;
	sum-=ans2*(1+ans2)/2;
	cout<<sum<<"\n";
}

E:

  • 很明显的线段树了。
  • 如果要求更改,就把整个区间的所有0异或结果和1异或结果换一下。
  • 因为涉及区间修改,需要用懒标记。
#include <bits/stdc++.h>
using namespace std;

const int N=1e5+6;
int ma1[4*N],ma2[4*N];
int lazy[4*N];
string s;
int a[N];
void pushup(int k){
	ma1[k]=ma1[2*k]^ma1[2*k+1];
	ma2[k]=ma2[2*k]^ma2[2*k+1];
}
void build(int k,int l,int r){
	lazy[k]=0;
	if(l==r){
		if(s[l]=='1') ma1[k]=a[l],ma2[k]=0;
		else ma2[k]=a[l],ma1[k]=0;
		return ;
	}
	int mid=(l+r)>>1;
	build(2*k,l,mid);
	build(2*k+1,mid+1,r);
	ma1[k]=ma1[2*k]^ma1[2*k+1];
	ma2[k]=ma2[2*k]^ma2[2*k+1];
}
void pushdown(int k){
	swap(ma1[2*k],ma2[2*k]);
	swap(ma2[2*k+1],ma1[2*k+1]);
	lazy[2*k]^=1;
	lazy[2*k+1]^=1;
	lazy[k]=0;
}
void change(int k,int l,int r,int x,int y){
	if(x<=l && r<=y){
		swap(ma1[k],ma2[k]);
		lazy[k]^=1;
		return ;
	}
	if(lazy[k]!=0) pushdown(k);
	int mid=(l+r)>>1;
	if(x<=mid) change(2*k,l,mid,x,y);
	if(y>mid) change(2*k+1,mid+1,r,x,y);
	pushup(k);
}

void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cin>>s;
	s="?"+s;
	int q;
	cin>>q;
	build(1,1,n);
	
	while(q--){
		int op; cin>>op;
		if(op==1){
			int l,r;cin>>l>>r;
			change(1,1,n,l,r);
			// cout<<ma1[1]<<"\n";
		}
		else{
			int g; cin>>g;
			if(g==1) cout<<ma1[1]<<" ";
			else cout<<ma2[1]<<" ";
		}
	}
	cout<<"\n";
}
signed main()
{
	cin.tie(0); ios::sync_with_stdio(false);
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

F:

  • 本身以为直接按照贪心就能过,结果别有洞天。
  • 对于点i,往\(a_i\)建立一条边,每一个点都会指向一个点,如果自己比指向的点在最后输出的前面,自己的价值就会翻倍。
  • 如果一个点度为0,说明没有人强制要求在此之前,可以直接输出。
    拓扑排序,把所有类似的都处理完之后。会只剩下一些环。
  • 为什么会只剩下一些环:
    • 可以对样例都画一下看看。
    • 因为整张图最多只有n条边,而且每一个点只有一个出度。
  • 如何处理剩下的环:
    对于一个环,里面一定是不能满足所有的都能翻倍的,至少有一个不能翻倍。
    可以发现,对于此题,所成环,一定为n个点,n条边,因此,一旦确定了一个不能翻倍之后,一定可以找到一种输出方式使得其他的都可以翻倍。
    所以只需要找到每一个环里面的点的价值最小的最后输出就好了。
#include <bits/stdc++.h>
using namespace std;

const int N=2e5+6;
vector<int>tr[N];
int vis[N],a[N],c[N];
int du[N];
int dfn[N],low[N],cnt;
int st[N];
int num,col[N];
vector<int>g[N];
stack<int>q;
void tarjan(int x){
	dfn[x]=low[x]=++cnt;
	q.push(x);
	st[x]=1;
	for(auto v:tr[x]){
		if(dfn[v]==0){
			tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if(st[v]) low[x]=min(low[x],dfn[v]);
	}
	if(dfn[x]==low[x]){
		num++;
		while(1){
			int t=q.top();
			q.pop();
			st[t]=0;
			col[t]=num;
			g[num].push_back(t);
			if(t==x) break;
		}
	}
}
void solve(){
	cnt=0; num=0;
	int n; cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		tr[i].push_back(a[i]);
		du[a[i]]++;
	}
	for(int i=1;i<=n;i++) cin>>c[i];
	
	vector<int>ans;
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(du[i]==0){	
			q.push(i); 
		} 
	}

	while(!q.empty()){
		int u=q.front(); q.pop();
		ans.push_back(u);
		for(auto v:tr[u]){
			du[v]--;
			if(du[v]==0) q.push(v);
		}
	}

	for(int i=1;i<=n;i++){
		if(dfn[i]==0) tarjan(i);
	}
	if(num>N-1){
		while(1);
	}
	for(int i=1;i<=num;i++){
		if(g[i].size()>1){
			int num_=0;
			int mina=1e9+1;
			for(auto v:g[i]){
				if(c[v]<mina){
					mina=c[v]; num_=v;
				}
			}
			int p=tr[num_][0];
			while(p!=num_){
				ans.push_back(p);
				p=tr[p][0];
			}
			ans.push_back(num_);
		}
	}
	for(auto v:ans){
		cout<<v<<" ";
	}
	cout<<"\n";
	for(int i=1;i<=n;i++){
		g[i].clear(); 
		tr[i].clear(); vis[i]=0; du[i]=0;
		st[i]=dfn[i]=low[i]=0; col[i]=0;
	}
}
int main()
{
	cin.tie(0); ios::sync_with_stdio(false);
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}