M-SOLUTIONS Programming Contest 2020 Solution

前言

第一次perf打满,好激动.

A A

显然相邻段位的上下界差200.
然后…

int n; qr(n);
pr2((1999-n)/200+1);

B B

已知 a , b , c , k a,b,c,k .
你现在有 k k 次操作,每次使得一个数乘2.
问最后可不可能 c > b > a c>b>a .

简单贪心.先让 b > a b>a ,再让 c > b c>b .

int main() {
	int a,b,c; qr(a); qr(b); qr(c);
	int n; qr(n);
	bool ans=1;
	while(n--) {
		if(b<=a) b*=2;
		else c*=2;
	}
	if(c>b&&b>a) puts("Yes");
	else puts("No");
	return 0;
}

C C

相邻两个的成绩有 k 1 k-1 个公共部分,比较不同的两个即可.

int n,m,a[N];
 
int main() {
	qr(n); qr(m);
	for(int i=1,x;i<=n;i++)qr(a[i]);
	for(int i=m+1;i<=n;i++)
		if(a[i]>a[i-m]) puts("Yes");
		else puts("No");
	return 0;
}

D D

贪心,低价买高价卖.

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	ll money=1000;
	int i=1;while(i<=n) {
		int j=i;
		while(j<=n&&a[j+1]>=a[j])j++;
		if(j>i)money=money/a[i]*a[j]+money%a[i];
		i=j+1;
	}
	pr2(money); return 0;
}

E E

简单状压.
定义 f [ i ] [ j ] f[i][j] 表示状态 i i , j j 条马路的最小代价.
首先,所有点求到 x , y x,y 轴的最小距离和.
然后我们每次考虑选择一些点计算贡献:
求贡献相当于求一下 x , y x,y 的中位数(相当于一个点上有很多个点)
然后求所有点到中位数的距离和即可.
我们预处理 w [ i ] w[i] 表示状态 i i 的最小开销.

则可以得到 D P DP 方程:
f [ i ] [ j ] = min { f [ k ] [ j 1 ] + w [ i xor k ] } ( k & j = k ) f[i][j]=\min \{f[k][j-1]+w[i \operatorname{xor} k]\}(k\& j=k) .

代码常数有点大…

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=17,size=1<<20,mod=998244353,inf=2e9;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

//math
ll mult(ll a,ll b,ll p) {
	a=(a%p+p)%p; b=(b%p+p)%p;
	ll c=(ld)a*b/p;
	return a*b-c*p;
}
ll gcd(ll a,ll b) {return !a?b:gcd(b%a,a);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=c*a%mod;
		b /= 2; a=a*a%mod;
	}
	return c;
}
ll Power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=mult(c,a,mod);
		b /= 2; a=mult(a,a,mod);
	}
	return c;
}

ll n,x[N],y[N],p[N],w[1<<N],f[1<<N][N],lg[1<<N];

struct rec {
	ll x,y;
	bool operator <(rec b) const {
		return x<b.x;
	}
} a[N];

ll calc(int now) {
	ll tot,s,ans=1e18,tmp,mid;
	
	tot=s=0;
	for(int i=0;i<n;i++)
		if(now>>i&1) a[++tot]=(rec){x[i],p[i]},s+=p[i];
	sort(a+1,a+tot+1);
	mid=s+1>>1;
	for(int i=1;i<=tot;i++)
		if(mid<=a[i].y) {
			tmp=0;
			for(int j=1;j<=tot;j++) tmp+=a[j].y*abs(a[i].x-a[j].x);
			ans=min(ans,tmp); break;
		}
		else mid-=a[i].y;
	
	tot=s=0;
	for(int i=0;i<n;i++)
		if(now>>i&1) a[++tot]=(rec){y[i],p[i]},s+=p[i];
	sort(a+1,a+tot+1);
	mid=s+1>>1;
	for(int i=1;i<=tot;i++)
		if(mid<=a[i].y) {
			tmp=0;
			for(int j=1;j<=tot;j++) tmp+=a[j].y*abs(a[i].x-a[j].x);
			ans=min(ans,tmp); break;
		}
		else mid-=a[i].y;
	
	return ans;
}

int main() {
	qr(n);
	for(int i=0;i<=n;i++) lg[1<<i]=i;
	for(int i=0;i<n;i++)
		qr(x[i]),qr(y[i]),qr(p[i]);
	int s=(1<<n)-1;
	memset(f,63,sizeof f);
	f[0][0]=0;
	for(int i=1;i<=s;i++) {
		f[i][0]=f[i&(i-1)][0];
		int j=lg[i&-i];
		f[i][0] += min(abs(x[j]),abs(y[j]))*p[j];
	}
	pr2(f[s][0]);
	for(int i=1;i<(1<<n);i++) w[i]=calc(i);
	for(int t=1;t<=n;t++) {
 		for(int i=1;i<=s;i++)
			for(int j=i;	;j=(j-1)&i) {
				f[i][t]=min(f[i][t],f[j][t-1]+w[i^j]);
				if(!j) break;
			}
		pr2(f[s][t]);
	}
	return 0;
}

F F

n ( n 2 1 0 5 ) n(n\le 2*10^5) 架飞机,现在已知他们的坐标和前进方向(上下左右),求最小撞机时间.

设0~3分别表示上下右左.以下简称向上的为0类点,以此类推.

撞击有两种:

  1. \rightarrow \leftarrow .
  2.    ~~\leftarrow
    \uparrow

第一种很容易处理,就是每个点按 x , y x,y 排序,判断 x   o r   y x ~or ~y 相同的情况.

观察第二种情况:两点间的斜率为 ± 1 \pm 1 .
处理的时候我们是按 x x 坐标非降,即从左往右处理.
我们可以定义 f [ i ] [ 0 / 1 ] , g [ i ] [ 0 / 1 ] f[i][0/1],g[i][0/1] .
f f 表示 2 2 类点的贡献, g g 表示 0 / 1 0/1 类点的贡献.
0 / 1 0/1 分别表示斜率为 + 1 , 1 +1,-1 .
i i 表示的是直线的截距.

举个例子:
      ~~~~~\leftarrow
  ~\uparrow \uparrow .
  ~\uparrow

假如有两架飞机和向左的飞机相撞,那么为了求最小时间,
我们应该记录每个 截距and斜率 对应状态的最大 x x 坐标.

对于各类点的处理细节:

  1. 和2类点可能相撞, 10 ( y f [ y x ] [ 1 ] ) 10(y-f[y-x][1]) 为撞击时间,同时有可能和后边的3类点相撞,所以更新 g [ y x ] [ 0 ] g[y-x][0]
  2. 类似0号点:和2类点可能相撞, 10 ( y f [ y + x ] [ 0 ] ) 10(y-f[y+x][0]) 为撞击时间,更新 g [ y + x ] [ 1 ] g[y+x][1] .
  3. 更新 f [ x + y ] [ 1 ] , f [ y x ] [ 0 ] f[x+y][1],f[y-x][0] .
  4. 可能和0/1类点相撞, 10 ( y g [ y x ] [ 0 ] ) , 10 ( y g [ y + x ] [ 0 ] ) 10(y-g[y-x][0]),10(y-g[y+x][0]) 为撞击时间.

细节: y x y-x 有可能下溢,所以给它加上 2 1 0 5 2*10^5 .

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=4e5+10,size=1<<20,mod=998244353;
const ll inf=1e18;

template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}


int n,dic[150],f[N*2][2],g[N*2][2];
ll ans=inf;
vector<pi> x[N],y[N];

int main() {
	qr(n);
	dic['U']=0;
	dic['D']=1;
	dic['R']=2;
	dic['L']=3;
	for(int i=1;i<=n;i++) {
		int a,b,c;qr(a); qr(b);
		char str[6]; scanf("%s",str);
		a++; b++; c=dic[str[0]];
		x[a].pb(mk(b,c));
		y[b].pb(mk(a,c));
	}
	for(int i=1;i<N;i++) {
		sort(all(x[i]));
		sort(all(y[i]));
		ll a,b;
		a=b=inf;
		for(auto j:x[i]) {
			if(j.se==0) a=j.fi;
			else if(j.se==1) b=j.fi;
			if(a<b) ans=min(ans,(b-a)*5);
		}
		a=b=inf;
		for(auto j:y[i]) {
			if(j.se==2) a=j.fi;
			else if(j.se==3) b=j.fi;
			if(a<b) ans=min(ans,(b-a)*5);
		}
	}
	for(int i=1;i<N;i++) 
		for(auto j:x[i]) {
			int t=j.fi;
			if(j.se==2) {
				f[j.fi-i+N][0]=i;
				f[j.fi+i][1]=i;
			}
			else if(j.se==3) {
				int k=g[j.fi+i][1];
				if(k) ans=min(ans,(i-k)*10LL);
				k=g[j.fi-i+N][0];
				if(k) ans=min(ans,(i-k)*10LL);
			}
			else if(j.se==1) {
				int k=f[j.fi-i+N][0];
				if(k) ans=min(ans,(i-k)*10LL);
				g[j.fi+i][1]=i;
			}
			else if(j.se==0) {
				int k=f[j.fi+i][1];
				if(k) ans=min(ans,(i-k)*10LL);
				g[j.fi-i+N][0]=i;
			}
		}
	if(ans>inf/2) puts("SAFE");
	else pr2(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/107588826