Codeforces Round #736 (Div. 2) 题解

传送门:https://codeforces.com/contest/1549

A

int main(){
	int T; cin>>T;
	while(T--){
		int x; cin>>x;
		cout<<2<<' '<<x-1<<endl;
	}	
    return 0;
}

B

贪心,能直走就直走,因为是从左到右扫过去,所以优先吃左边的,如果左边没有右边有就吃右边的。

int main(){
	int T; cin>>T;
	while(T--){
		int n; cin>>n;
		string a, b; cin>>a>>b;
		a='#'+a+'#', b=' '+b;
		
		int res=0;
		rep(i,1,n) if(b[i]=='1'){
			if(a[i]=='0'){
				a[i]='#';
				res++;
				continue;
			}
			
			if(a[i-1]=='1'){
				a[i-1]='#';
				res++;
				continue;
			}
			
			if(a[i+1]=='1'){
				a[i+1]='#';
				res++;
				continue;
			}
		}
		
		cout<<res<<endl;
	}	
    return 0;
}

C

维护 \(n\) 个点对应的集合。

注意到如果一个点它自己的集合内存在比它编号大的元素,那么它就会被干掉。

所以我们先通过初始关系维护一个初始的存活集合个数 \(cur\),然后对于每次查询我们都更新一下发生修改的集合以及 \(cur\) 即可。

#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define debug(x) cerr << #x << ": " << x << endl
#define pb(a) push_back(a)
#define set0(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define ceil(a,b) (a+(b-1))/b
#define INF 0x3f3f3f3f
#define ll_INF 0x7f7f7f7f7f7f7f7f
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;

inline void read(int &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=2e5+50;
set<int> g[N];

int main(){
	int n, m; cin>>n>>m;
	rep(i,1,m){
		int u, v; read(u), read(v);
		g[u].insert(v);
		g[v].insert(u);
	}
	
	int cur=0;
	
	rep(i,1,n) if(g[i].size()){
		if(*g[i].rbegin()<i) cur++; 
	}else cur++;
	
	int q; cin>>q;
	while(q--){
		int op; read(op);
		if(op==1){
			int u, v; read(u), read(v);
			if(u>v) swap(u, v);
			
			bool ok=1;
			if(g[u].size() && *g[u].rbegin()>u) ok=0;
			
			g[u].insert(v);
			g[v].insert(u);
			
			cur-=ok;
		}
		else if(op==2){
			int u, v; read(u), read(v);
			if(u>v) swap(u, v);

			g[u].erase(v);
			g[v].erase(u);
			
			if(!g[u].size()) cur++;
			else if(*g[u].rbegin()<u) cur++;
		}
		else cout<<cur<<endl;
	}
    return 0;
}

D

假设选取了 \([l, r]\) 这一段,那么这一段是满足题意的子段当且仅当 \(gcd_{i=l+1}^r d_i\neq1\),其中 \(d\) 代表序列 \(d_{i}-d_{i-1}\)\(i\in [2,n]\))。

所以我们的做法是用 st 表维护一下区间 \(gcd\) 值,然后枚举序列 \(d\) 左端点,看看右端点最远的位置使得 \(gcd\) 值不为 \(1\),这是满足二段性的所以可以用二分来做。

当然,如果得到区间长度至少为 \(1\),如果这个数 \(gcd\) 本来就是 \(1\) 就要跳过(不更新答案)。

#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define debug(x) cerr << #x << ": " << x << endl
#define pb(a) push_back(a)
#define set0(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define ceil(a,b) (a+(b-1))/b
#define INF 0x3f3f3f3f
#define ll_INF 0x7f7f7f7f7f7f7f7f
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;

#define int long long

inline void read(int &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=6e5+5, M=25;

int w[N], d[N];
int n, logn[N<<2];
int st[N][M];

int gcd(int a, int b){
	return b? gcd(b, a%b): a;
}

void init(){
    for(int i=2;i<=n;i++) logn[i]=logn[i/2]+1;

    for(int j=0;j<M;j++)
        for(int i=2;i+(1<<j)-1<=n;i++)
            if(!j) st[i][j]=d[i];
            else st[i][j]=gcd(st[i][j-1],st[i+(1<<j-1)][j-1]);
}

int query(int l,int r){
    int len=r-l+1;
    int k=logn[len];
    return gcd(st[l][k],st[r-(1<<k)+1][k]); 
}

signed main(){
	int T; cin>>T;
	while(T--){
		read(n);
		rep(i,1,n) read(w[i]);
		rep(i,2,n) d[i]=w[i]-w[i-1];
		
		init();
		
		int res=1;
		rep(i,2,n){
			int l=i, r=n;
			while(l<r){
				int mid=l+r+1>>1;
				if(abs(query(i, mid))!=1) l=mid;
				else r=mid-1;
			}
			
			if(abs(query(i, i))==1) continue; 
			else res=max(res, l-i+1+1); 
		}
		cout<<res<<endl;
	}	
    return 0;
}
posted @ 2021-08-02 10:50  HinanawiTenshi  阅读(55)  评论(0编辑  收藏  举报