【CF套题】Good Bye 2018

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85488631

【前言】
自闭了,四题以后就看着排名一直往下掉。
E想了个线段树维护阶梯,没看wiki,出来才发现是公式题。
F想了个凸包,结果是个贪心。
心态炸裂(然而rk500还能涨分)

【题目】
原题地址

A.New Year and the Christmas Ornament

瞎搞。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
int a,b,c,t;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
#endif
	a=read();b=read();c=read();
	t=min(a+2,b+1);t=min(t,c);
	if(t<0) t=0;
	printf("%d\n",t+t+t-3);

	return 0;
}

B.New Year and the Treasure Geolocation

排序后首尾相加即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1005;
int n;
pii a[N],b[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
#endif
	n=read();
	for(int i=1;i<=n;++i) a[i].fi=read(),a[i].se=read();
	for(int i=1;i<=n;++i) b[i].fi=read(),b[i].se=read();
	sort(a+1,a+n+1);sort(b+1,b+n+1);
	printf("%d %d\n",a[1].fi+b[n].fi,a[1].se+b[n].se);
	return 0;
}

C.New Year and the Sphere Transmission

枚举 n n 的所有约数,等差数列求和后去重即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e6+10;
int n,cnt;
ll a[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
#endif
	n=read();
	for(int i=1,j;(ll)i*i<=n;++i)
	{
		if(n%i) continue;
		a[++cnt]=(ll)(1+n-i+1)*(n/i)/2;
		if(i*i!=n) j=n/i,a[++cnt]=(ll)(1+n-j+1)*(n/j)/2;
	}
	sort(a+1,a+cnt+1);
	for(int i=1;i<=cnt;++i) if(a[i]!=a[i-1]) printf("%lld ",a[i]);

	return 0;
}

D.New Year and the Permutation Concatenation

考虑枚举将去掉多长的前缀后后面的排列恰好补充前面的,则答案是 n n ! k = 1 n 1 n ! k ! n \cdot n! - \sum_{k=1}^{n-1} \frac{n!}{k!}

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,mod=998244353;
const int N=1e6+10;
ll n,ans,fac[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("D.in","r",stdin);
	freopen("D.out","w",stdout);
#endif
	n=read();
	fac[0]=1;for(int i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%mod;
	ll t=1;
	for(int i=1;i<n;++i) 
	{
		t=t*(n-i+1)%mod;
		ans=(ans+(ll)t*(fac[n-i]-1)%mod)%mod;
	}
	ans=(ans+fac[n])%mod;
	printf("%lld\n",(ans%mod+mod)%mod);
	return 0;
}

E.New Year and the Acquaintance Estimation

Erdős–Gallai theorem
结论是对于一个从大到小排序后的度数序列 d d ,能构成简单图当且仅当:
i = 1 k d i ( k ( k 1 ) + j = k + 1 n min ( d j + k ) ) \sum_{i=1}^k d_i\leq (k(k-1)+\sum_{j=k+1}^n \min(d_j+k)) 对于 1 k n 1\leq k\leq n 均成立。
答案显然是一个公差为 2 2 的等差序列,我们二分答案的上下界,上述式子不成立时,若第 n + 1 n+1 个点已满足条件,说明答案太大,否则说明答案太小。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e6+10;
int n;
ll a[N],b[N],s[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

void solve()
{
	n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	sort(a+1,a+n+1);
	for(int i=1;i<=n;++i) s[i]=s[i-1]+a[i];
	for(int i=1,j=1;i<=n;++i)
	{
		ll l=s[n]-s[n-i],r=(ll)i*(i-1);
		while(j<=n && a[j]<i) ++j;
		r+=s[min(j-1,n-i)]+(ll)max(0,n-i-j+1)*i;
		ll now=a[n-i+1],tmp=l-r;
		if(tmp<=i && tmp<=now) ++b[max(tmp,0ll)],--b[now+1];
		l-=a[n-i+1];r+=min(a[n-i+1],(ll)i);
		tmp=r-l;
		if(tmp>=now+1) ++b[now+1],--b[min(tmp+1,(ll)n+1)];
	}
}
void printans()
{
	ll sum=0,hv=0;
	for(int i=0;i<=n;++i)
	{
		sum+=b[i];
		if(sum==n && s[n]%2==i%2) ++hv,printf("%d ",i);
	}
	if(!hv) puts("-1");
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("E.in","r",stdin);
	freopen("E.out","w",stdout);
#endif
	solve();
	printans();

	return 0;
}

F.New Year and the Mallard Expedition

考虑这样一个贪心:如果我们没有体力,我们可以通过往回游半米再游回去补充体力,而这可以在第一个水中进行。如果第一个岩浆之前没有水,就在草地上走路。此外,如果有未用的体力,应当将之前一些动作转化为飞,显然应更多转化走路。

那么我们到每个格子先将可行的所有走路和游泳距离计算出。假设我们整个过程都是飞行的,那么我们需要足够体力,于是我们贪心地将一些飞行用游泳和走路来代替。如果到了某个格子发现体力无论如何都不够而不能飞了,我们再来回游泳转化为飞行即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e5+10;
int n;
ll ans,G,W,l[N];
char s[N];

ll read()
{
	ll ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("F.in","r",stdin);
	freopen("F.out","w",stdout);
#endif
	n=read();
	for(int i=1;i<=n;++i) l[i]=read()*2,ans+=l[i];
	scanf("%s",s+1);
	for(int i=1,tim=5;i<=n;++i)
	{
		if(s[i]=='G') G+=l[i];
		else if(s[i]=='W') W+=l[i],tim=3;
		ll res=l[i],t;
		t=min(res/2,W);ans+=t*2;res-=t*2;W-=t;
		t=min(res/2,G);ans+=t*4;res-=t*2;G-=t;
		ans+=res*tim;
	}
	printf("%lld\n",ans/2);
	return 0;
}

G.New Year and the Factorisation Collaboration

官方题解
太长了看不懂。
然后,论python的优越性。

这是别人的c++

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define db long double
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define MK make_pair
#define LB lower_bound
#define UB upper_bound
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define UPD(x,y) (((x)+=(y))>=mo?x-=mo:233)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
using namespace std;
const int LEN=80;
const int YW=8;
const int BAS=100000000;
struct big{
	int a[LEN];
	//delete .a[]
	int& operator [](int x){
		return a[x];
	}
	const int& operator [](int x)const{
		return a[x];
	}
	
	//getnum
	big(){
		CLR(a,0);
	}
	big operator =(const big &x){
		For(i,x[0]+1,a[0]) a[i]=0;
		For(i,0,x[0]) a[i]=x[i];
		return *this;
	}
	big operator =(int x){
		Rep(i,a[0],0) a[i]=0;
		for (;x;x/=BAS)
			a[++a[0]]=x%BAS;
		return *this;
	}
	big(int x){
		CLR(a,0);
		*this=x;
	}
	
	//compare
	bool operator <(const big &b)const{
		if (a[0]!=b[0]) return a[0]<b[0];
		Rep(i,a[0],1) if (a[i]!=b[i]) return a[i]<b[i];
		return 0;
	}
	bool operator >(const big &b)const{
		if (a[0]!=b[0]) return a[0]>b[0];
		Rep(i,a[0],1) if (a[i]!=b[i]) return a[i]>b[i];
		return 0;
	}
	bool operator <=(const big &b)const{
		return !(*this>b);
	}
	bool operator >=(const big &b)const{
		return !(*this<b);
	}
	bool operator ==(const big &b)const{
		return !(*this>b)&&!(*this<b);
	}
	bool operator !=(const big &b)const{
		return !(*this==b);
	}
	
	//cheng
	big operator *(const big &b)const{
		big c; c[0]=a[0]+b[0];
		For(i,1,a[0]) For(j,1,b[0]){
			ll x=c[i+j-1]+1ll*a[i]*b[j];
			c[i+j]+=x/BAS; c[i+j-1]=x%BAS;
		}
		for (;c[0]>0&&!c[c[0]];c[0]--);
		return c;
	}
	big operator *(int x)const{
		big c; ll v=0;
		For(i,1,a[0]+3){
			v=1ll*x*a[i]+v;
			c[i]=v%BAS; v/=BAS;
		}
		c[0]=a[0]+3;
		for (;c[0]>0&&!c[c[0]];c[0]--);
		return c;
	}
	
	//chu
	big operator /(int x)const{
		big c; ll v=0;
		Rep(i,a[0],1){
			v=v*BAS+a[i];
			c[i]=v/x; v%=x;
		}
		c[0]=a[0];
		for (;c[0]>0&&!c[c[0]];c[0]--);
		return c;
	}
	big operator /(const big &b)const{
		if (b[0]==1&&!b[1]){
			puts("error! divide by 0");
			exit(0);
		}
		if (*this<b) return big(0);
		int l1=max(0,(a[0]-1))*YW;
		int l2=max(0,(b[0]-1))*YW;
		int v1=a[a[0]],v2=b[b[0]];
		for (;v1;v1/=10,l1++);
		for (;v2;v2/=10,l2++);
		big c,chu=*this,B=b;
		For(i,1,(l1-l2)/YW) B*=BAS;
		For(i,1,(l1-l2)%YW) B*=10;
		Rep(i,l1-l2,0){
			int x=0;
			for (;chu>=B;chu-=B,x++);
			c[i/YW+1]=c[i/YW+1]*10+x;
			B/=10;
		}
		c[0]=(l1-l2)/YW+1;
		for (;c[0]>0&&!c[c[0]];c[0]--);
		return c;
	}
	
	//jia
	big operator +(const big &b)const{
		big c; c[0]=max(a[0],b[0]);
		For(i,1,c[0]) c[i]=a[i]+b[i];
		For(i,1,c[0]) c[i+1]+=c[i]/BAS,c[i]%=BAS;
		if (c[c[0]+1]) c[0]++;
		return c;
	} 
	big operator +(int x)const{
		big c=*this; c[1]+=x;
		For(i,1,c[0]+1)
			if (c[i]>=BAS){
				c[i+1]+=c[i]/BAS;
				c[i]%=BAS;
			}
			else break;
		if (c[c[0]+1]) c[0]++;
		return c;
	}
	
	//jian
	big operator -(const big &b)const{
		big c; c[0]=a[0];
		For(i,1,c[0]) c[i]=a[i]-b[i];
		For(i,1,c[0]) if (c[i]<0)
			c[i]+=BAS,c[i+1]--;
		for (;c[0]>1&&!c[c[0]];c[0]--);
		return c;
	}
	big operator -(int x)const{
		big c=*this; c[1]-=x;
		For(i,1,c[0]+1)
			if (c[i]<0){
				c[i+1]+=(c[i]+1)/BAS-1;
				c[i]=(c[i]+1)%BAS+BAS-1;
			}
			else break;
		for (;c[0]>1&&!c[c[0]];c[0]--);
		return c;
	}
	
	//mod
	int operator %(int x)const{
		ll ans=0;
		Rep(i,a[0],1)
			ans=(ans*BAS+a[i])%x;
		return ans;
	}
	big operator %(const big &b)const{
		if (b[0]==1&&!b[1]){
			puts("error! mod by 0");
			exit(0);
		}
		if (*this<b) return *this; 
		int l1=max(0,(a[0]-1))*YW;
		int l2=max(0,(b[0]-1))*YW;
		int v1=a[a[0]],v2=b[b[0]];
		for (;v1;v1/=10,l1++);
		for (;v2;v2/=10,l2++);
		big chu=*this,B=b;
		For(i,1,(l1-l2)/YW) B*=BAS;
		For(i,1,(l1-l2)%YW) B*=10;
		Rep(i,l1-l2,0){
			for (;chu>=B;chu-=B);
			B/=10;
		}
		return chu;
	}
	
	//suoxie
	big operator +=(const big &b){
		return *this=(*this+b);
	}
	big operator -=(const big &b){
		return *this=(*this-b);
	}
	big operator *=(const big &b){
		return *this=(*this*b);
	}
	big operator /=(const big &b){
		return *this=(*this/b);
	}
	big operator %=(const big &b){
		return *this=(*this%b);
	}
	big operator +=(int x){
		return *this=(*this+x);
	}
	big operator -=(int x){
		return *this=(*this-x);
	}
	big operator *=(int x){
		return *this=(*this*x);
	}
	big operator /=(int x){
		return *this=(*this/x);
	}
	
	//IO
	void read(){
		char c[LEN*YW+10];
		scanf("%s",c);
		int len=strlen(c);
		CLR((*this).a,0);
		reverse(c,c+len);
		a[0]=(len-1)/YW+1;
		Rep(i,len-1,0)
			a[i/YW+1]=a[i/YW+1]*10+c[i]-'0';
	}
	void write()const{
		printf("%d",a[a[0]]);
		Rep(i,a[0]-1,1) printf("%08d",a[i]);
	}
	void writeln()const{
		write(); puts("");
	}
};
big gcd(const big &a,const big &b){
	big A=a,B=b,ans=1;
	for (;!(A[1]&1)&&!(B[1]&1);A/=2,B/=2,ans*=2);
	for (;;){
		if (A[0]==1&&A[1]==0) return B*ans;
		if (B[0]==1&&B[1]==0) return A*ans;
		for (;!(A[1]&1);A/=2);
		for (;!(B[1]&1);B/=2);
		A>B?A-=B:B-=A;
	}
}
big q[233];
big ans[233];
int tp,tot;
int rnd(int md){
	int x=0;
	For(i,1,100) x=(x*10ll+rand()%10)%md;
	return x;
}
big make(big n){
	big x; x=n;
	x[x[0]]=rnd(x[x[0]]);
	For(j,1,x[0]-1) x[j]=rnd(BAS);
	for (;x[0]>1&&!x[x[0]];x[0]--);
	if (x[0]==1&&!x[1]) x[1]++;
	return x;
}
void insert(const big &a){
	//printf("insert "); a.writeln();
	int pos=++tp; q[tp]=a;
	Rep(i,pos-1,1){
		big G=gcd(q[i],q[pos]);
		if (G==1) continue;
		q[i]/=G; q[pos]/=G; q[++tp]=G;
	}
	pos=0;
	For(i,1,tp)
		if (q[i]!=1)
			q[++pos]=q[i];
	tp=pos;
	//printf("%d\n",pos);
	//For(i,1,tp)
	//	q[i].writeln();
}
int main(){
	srand(time(NULL)); 
	big n; n.read();
	q[++tp]=n;
	For(i,1,10){
		big x=make(n);
		for (;gcd(x,n)!=1;){
			insert(gcd(x,n));
			x=make(n);
		} 
		big y=x*x%n;
		printf("sqrt ");
		y.writeln();
		fflush(stdout);
		big z; z.read();
		if (z!=x&&z!=n-x){
			big v1=(x+z)%n;
			insert(gcd(n,v1));
		}
	}
	printf("! %d ",tp);
	for (int i=1;i<=tp;i++)
		q[i].write(),putchar(' ');
}
/*
1:1,20,8,13
4:2,19,5,16
7:7,14
9:3,18
15:6,15
16:4,17,10,11
18:9,12
if (gcd(i,v[i])==1) continue;
else{
	erase(v[i]);
	push(v[i]/G,i/G,G)
}
*/

这是别人的python

import random
import sys

def gcd(x, y):
    while y:
        t = x % y
        x = y
        y = t
    return x

n = int(raw_input())
candidates = []
factors = []
for i in range(30):
    x = random.randint(1, n - 1)
    y = x * x % n
    print "sqrt " + str(y)
    sys.stdout.flush()
    y = int(raw_input())
    if x != y:
        if x > y:
            x, y = y, x
        candidates.append(y - x)

def divide(n):
    for d in candidates:
        g = gcd(n, d)
        if g != 1 and g != n:
            divide(g)
            divide(n / g)
            return
    factors.append(n)

divide(n)
answer = "! " + str(len(factors))
for x in factors:
    answer += " " + str(x)
print answer

H.New Year and the Tricolore Recreation

满足条件的 k k 显然我们可以用线性筛求出来。
每个游戏可以用一个二元组 ( x , y ) (x,y) 来表示差值,每次操作实际上双方都可以将 x x y y 减去 k k ,这就十分对称了。接下来显然每个游戏是独立的,那么这就十分 Nim \text{Nim} 了,于是实际上一个二元组也可以拆成两个游戏。
现在我们有一个 SG \text{SG} 值不超过 1 0 5 10^5 的游戏了,我们可以暴力做到 O ( m 2 ) O(m^2) ,其中 m m 是两棋子间最大距离( 2 × 1 0 5 2\times 10^5 )。过不了过不了。
然后我们维护 k k bitset \text{bitset} ,第 i i bitset \text{bitset} 的第 j j 位为 1 1 ,当且仅当状态 j j i i 这个后继状态( SG \text{SG} )。
然后我们维护一个所有素数和素数乘积的 bitset \text{bitset} P P ,对于每个状态 i i ,我们给第 j j bitset \text{bitset} 或上 P P 左移 i i 位即可。
可以(打表)证明 SG \text{SG} 函数值最多 100 100 ,于是我们就可以玄学过了。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=2e5+10,K=100;
int n,f,pnum,ans,sg[N],pri[N],bo[N];
bitset<N>G[K],P;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

void getp()
{
	for(int i=2;i<N;++i)
	{
		if(!bo[i]) pri[++pnum]=i,P[i]=1;
		for(int j=1;j<=pnum && (ll)i*pri[j]<N;++j)
		{
			bo[i*pri[j]]=1;
			if(!bo[i]) P[i*pri[j]]=1;
			if(!(i%pri[j])) break;
		}
	}
}
void solve()
{
	n=read();f=read();P[f]=0;
	sg[0]=sg[1]=0;G[0]|=P|(P<<1);
	for(int i=2;i<N;++i) 
	{
		while(G[sg[i]][i]) ++sg[i];
		G[sg[i]]|=P<<i;
	}

	for(int i=1;i<=n;++i)
	{
		int a=read(),b=read(),c=read();
		ans^=sg[b-a-1]^sg[c-b-1];
	}
	if(ans) puts("Alice\nBob");
	else puts("Bob\nAlice");
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("H.in","r",stdin);
	freopen("H.out","w",stdout);
#endif
	getp();solve();
	return 0;
}

【总结】
HELLO 2019 见。

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85488631