May Challenge 2019 Division 2 水题讲解

Reduce to One

这题其实蛮水的?

题意就是说:

给定一个 1~n 的序列,每次挑两个数 x y 合并,合并值为 \(x+y+xy\) ,然后求不断合并最后剩下的一个的最大值

随便搞搞发现答案应该是无论怎么合并都一样的,所以从左到右合并就好了,加上是第一题,大概就是这个结论

于是前缀信息处理一下每次直接输出就好了...


//by Judge
#include<bits/stdc++.h>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
using namespace std;
const int mod=1e9+7;
const int M=1e6+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){ int x=0,f=1; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int CCF=-1,Z;
inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
inline void print(int x,char chr='\n'){
	if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
	while(z[++Z]=x%10+48,x/=10);
	while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
} int n; arr q,f;
inline int mul(Rg int x,Rg int y){return 1ll*x*y%mod;}
inline int inc(Rg int x,Rg int y){return (x+=y)>=mod?x-mod:x;}
int main(){ Rg int T=read();
	fp(i,1,T) q[i]=read(); n=*max_element(q+1,q+1+T);
	fp(i,1,n) f[i]=inc(inc(f[i-1],i),mul(i,f[i-1]));
	fp(i,1,T) print(f[q[i]]); return Ot(),0;
}

Matches

给出两堆火柴,每次取某堆火柴的一定数,这个数字要能整除另一堆火柴的个数,谁先取完某一堆的获胜

貌似是博弈论,看看这整除好像和 gcd 很有关的样子,于是发现先掌握主动权的人必胜(就是说轮到某人取的时候,某一堆火柴整除另一堆火柴的个数大于 1 ,那么这个人就可以完全控制局面了),然后加些特判就 ok 了,复杂度带个 log 但常数真的小

//by Judge
#include<cstdio>
#include<cstring>
#include<iostream>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
#define ll long long
using namespace std;
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline ll read(){ ll x=0,f=1; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} ll n,m,ans;
#define swap(a,b) (a)^=(b)^=(a)^=(b)
int main(){
	fp(i,1,read()){ n=read(),m=read();
		if(n<m) swap(n,m); ans=1;
		if(n%m==0){
			puts("Ari");
			goto end;
		}
		while(n<m<<1) n-=m,swap(n,m),ans^=1;
		puts(ans?"Ari":"Rich");
		end:;
	} return 0;
}

Where to Build the Roads

给出 n 个二维点,你可以放置 n-1 条斜率为 1 或 -1 的直线,然后要让所有点里最近的直线距离中的最大值最小,并输出这个最小值乘上根号 2 的值,即求

\[ans=\sqrt2Min(~~~ MAX_{i=1}^n(dis _ i )~~~ ) \]

然后我们发现只要求出所有的两个点之间的 \({||x1-x2| -|y1-y2|| \over 2} + Min(|x1-x2|,|y1-y2|)\) 的最小值

然鹅 \(n^2\) 枚举就完蛋了,于是我们发现只需要经过每个点记录下该点的两条斜率为 -1 和 1 的直线,然后所有斜率相同的直线排个序,求两条相邻直线 \(y_1=(±1)x_1+b_1,y_2=(±1)x_2+b_2\)\(|b_2-b_1|\)的最小差值就是答案了

//by Judge
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
using namespace std;
const int M=1e4+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline bool cmin(int& a,int b){return a>b?a=b,1:0;}
inline int read(){ int x=0,f=1; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} int n,ans; arr x,y,a,b;
int main(){
	fp(i,1,read()){ n=read(),ans=1e9;
		fp(i,1,n) x[i]=read(),y[i]=read(),a[i]=y[i]-x[i],b[i]=x[i]+y[i];
		sort(a+1,a+1+n),sort(b+1,b+1+n);
		fp(i,2,n) cmin(ans,a[i]-a[i-1]),cmin(ans,b[i]-b[i-1]);
		printf("%.8lf\n",ans/2.0);
	} return 0;
}

关于其他题目可能可以看看博主博客园里面有没有写

posted @ 2019-05-14 16:41  Jμdge  阅读(185)  评论(0编辑  收藏  举报