2018-2019 XIX Open Cup, Grand Prix of Korea 解题报告

H

我们枚举化简后有多少对(x'=frac{x}{gcd(i,j)})(y'=frac{y}{gcd(i,j)}),然后就可以得出有多少(gcd(i,j))满足条件。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

ll A,B,C,D;

int main(){
	A=input(),B=input(),C=input(),D=input();

	ll Ans=0;

	for(int i=1;i<1000;i++){
		for(int j=1;j+i<1000;j++){
			if(__gcd(i,j)!=1) continue;
			// cout<<(D/j)<<" "<<(B/i)<<" "<<(A-1)/i<<" "<<(C-1)/j<<endl;
			ll tmp=min((D/j),(B/i))-max((A-1)/i,(C-1)/j);
			// if(tmp>0)cout<<tmp<<endl;
			if(tmp<=0) continue;
			Ans+=tmp;
		}
	}
	printf("%lld
",Ans);
}

F

签到题,递归构造,重复利用即可。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=2e5+7;
ll id,ls[N],rs[N];
map <ll,int> mp;

void init(){mp.clear();id=-1;}

void dfs(ll n){
	if(mp.find(n)!=mp.end()) return;
	if(n==1){
		mp[n]=++id,ls[id]=-1,rs[id]=-1;
		return;
	}
	dfs(n-n/2),dfs(n/2);
	mp[n]=++id,ls[id]=mp[n-n/2],rs[id]=mp[n/2];
}

int main(){
	int T=input();
	while(T--){
		init();
		ll n=input();
		dfs(n);
		printf("%lld
",id+1);
		for(int i=0;i<=id;i++){
			printf("%lld %lld
",ls[i],rs[i]);
		}
		printf("%lld
",id);
	}
}

L

预处理出,每个点向右不递减最远到达的距离和严格递减到达的距离。对于每个询问暴力的处理块数和坏数的个数,然后记忆化答案。复杂度是调和级数的复杂度O(nlogn)。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=1e5+7;

int n,m;
int a[N],mx[N],mi[N];
int Ans[N],block[N];

int main(){
	n=input();

	for(int i=1;i<=n;i++) a[i]=input(),Ans[i]=-1,block[i]=0;

	for(int i=1;i<=n;){
		int len=0,id=i;
		for(int j=i+1;j<=n;j++){
			if(a[j]>=a[j-1]) len++,id=j;
			else break;
		}

		for(int j=i;j<=id;j++) mx[j]=id;
		i=id+1;
	}
    for(int i=1;i<=n;){
        int len=0,id=i;
        for(int j=i+1;j<=n;++j){
            if(a[j]<a[j-1]) len++,id=j;
            else break;
        }
        for(int j=i;j<=id;++j)mi[j]=id;
        i=id+1;
    }

    int Q=input();

    for(int i=1;i<=Q;i++){
    	int mr=input();
    	if(Ans[mr]!=-1){
    		printf("%d %d
",block[mr],Ans[mr]);
    	}else{
    		int cnt=0,bad=0;
    		for(int i=1;i<=n;){
    			int tmp=max(mx[i],mi[i]);
    			int to=min(i+mr-1,n);
    			// cout<<i<<":tmp="<<tmp<<" to="<<to<<endl;
    			if(tmp>=to){
    				cnt++;
    				i=tmp+1;
    			}else{
    				cnt++;
    				bad+=(to-tmp);
    				i=to+1;
    			}
    			// cout<<"bad="<<bad<<" cnt="<<cnt<<endl;
    		}
    		printf("%d %d
",block[mr]=cnt,Ans[mr]=bad);
    	}
    }

}

I

sg函数,一直不太擅长这套理论,在这里学到了许多。在这里每加一条线相当于增加了两个后继局面,(j)(i-j-2),然后就是传统的sg函数推导了。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=5007;

int f[N],S[N],sg[N];

void init(){
	memset(sg,0,sizeof sg);

	sg[1]=0,sg[2]=1;

	for(int i=3;i<N;i++){
		memset(S,0,sizeof(S));
		for(int j=0;j<=i-2;j++)
			S[sg[i-j-2]^sg[j]]=1;
		for(int j=0;;j++)
			if(!S[j]){sg[i]=j;break;}
	}
}

int main(){
	init();

	int T=input();
	while(T--){
		int n=input();
		if(sg[n]) printf("First
");
		else printf("Second
");
	}
}

E

阅读理解题,英语、语文都不太好,死活读不懂题意。

题意:n个点,m条边,要求判断是否仅存在串联和并联并且有从源点到汇点使得图是一个简单电路

题解:对于一条链可以压缩为直接一条边到达,不断压缩后判断是否只有源点和汇点即可。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=1e5+7;

int n,m,cnt;
int vis[N];
set <int> G[N];

void del(int x){
	if(G[x].size()==2){
		vis[x]=1,cnt--;
		int u=*G[x].begin();
		int v=*G[x].rbegin();
		G[u].erase(x),G[v].erase(x);
		G[u].insert(v),G[v].insert(u);
		if(!vis[u]) del(u);
		if(!vis[v]) del(v);
	}
}

int main(){
	int n=input(),m=input();
	for(int i=1;i<=m;i++){
		int u=input(),v=input();
		G[u].insert(v),G[v].insert(u);
	}

	cnt=n;
	for(int i=1;i<=n;i++){
		if(!vis[i]) del(i);
	}

	if(cnt==2) printf("Yes
");
	else printf("No
");
}
原文地址:https://www.cnblogs.com/-aether/p/13282004.html