2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017)

Claris發表於2017-11-01

A. Alien Sunset

暴力列舉答案即可。

#include<cstdio>
int n,i,mx;
struct P{
	int h,r,t;
	bool night(int x){
		x%=h;
		if(r<=t)return x<=r||x>=t;
		return x<=r&&x>=t;
	}	
}a[50];
inline bool check(int x){
	for(int i=0;i<n;i++)if(!a[i].night(x))return 0;
	return 1;
}
int main(){
	scanf("%d",&n);
	for(i=0;i<n;i++){
		scanf("%d%d%d",&a[i].h,&a[i].r,&a[i].t);
		if(a[i].h>mx)mx=a[i].h;
	}
	for(i=0;i<1825*mx;i++)if(check(i))return printf("%d",i),0;
	puts("impossible");
}

  

B. Breaking Biscuits

等價於選擇一對距離最小的平行線夾住所有點。

列舉一條邊,計算兩側所有點到這條直線的距離的最大值即可。

時間複雜度$O(n^3)$。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=111;
struct P{
	int x,y;
	P(){}
	P(int _x,int _y){x=_x,y=_y;}
	P operator-(P b){return P(x-b.x,y-b.y);}
	double len(){return hypot(x,y);}
}a[N];
int n,i,j,k;
double cross(P a,P b){return a.x*b.y-a.y*b.x;}
double dist(P p,P a,P b){
	return cross(p-a,b-a)/(b-a).len();
}
int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
	double ans=1e100;
	a[n+1]=a[1];
	for(i=1;i<=n;i++)for(j=1;j<i;j++){
		double l=1e100,r=-1e100;
		for(k=1;k<=n;k++){
			l=min(l,dist(a[k],a[i],a[j]));
			r=max(r,dist(a[k],a[i],a[j]));
		}
		r-=l;
		ans=min(ans,r);
	}
	printf("%.10f",ans);
}

  

C. Cued In

按題意模擬即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
const int N = 3e5 + 10;
const int inf = 1e9;
int casenum, casei;
int c[2010], e[15];
int n;
map<string, int> mop;
int num[10];
char s[20];
int main()
{
	mop["red"] = 1; mop["yellow"] = 2; mop["green"] = 3; mop["brown"] = 4;
	mop["blue"] = 5; mop["pink"] = 6; mop["black"] = 7;
	while(~scanf("%d", &n)){
		for(int i = 1; i <= n; i ++){
			scanf("%s", s);
			num[mop[s]] ++;
		}
		int top = 1;
		for(int i = 2; i <= 7; i ++){
			if(num[i]) top = i;
		}
		if(top == 1) puts("1");
		else{
			int ans = 0;
			ans = (1 + top) * num[1];
			for(int i = 2; i <= 7; i ++) ans += num[i] * i;
			printf("%d\n", ans);
		}
		
		
	}
	return 0;
}
/*


*/

  

D. Deranging Hat

求出最終位置,然後貪心置換即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
const int N = 1e5 + 10;
char s[N];
struct A
{
	char ch;
	int now;
	bool operator < (const A & b)const
	{
		if(ch != b.ch)return ch < b.ch;
		return now < b.now;
	}
}a[N];
int pos_to_o[N];
int main()
{
	while(~scanf("%s", s))
	{
		int n = strlen(s);
		for(int i = 0; i < n; ++i)
		{
			a[i].ch = s[i];
			a[i].now = i;
		}
		sort(a, a + n);
		for(int i = 0; i < n; ++i)
		{
			pos_to_o[a[i].now] = i;
		}
		vector<pair<int, int> >ans;
		for(int i = 0; i < n; ++i)
		{
			//我們要考慮移動,把位置為a[i].now的數,移動到位置i,那位置i的數的位置變成了a[i].now
			if(a[i].now != i)
			{
				ans.push_back(make_pair(i, a[i].now));
				int p = a[i].now;
				int o = pos_to_o[i];
				a[o].now = a[i].now;
				pos_to_o[p] = o;
			}
		}
		int g = ans.size() - 1;
		for(int i = g; i >= 0; --i)
		{
			printf("%d %d\n", ans[i].second + 1, ans[i].first + 1);
		}
	}
	return 0;
}
/*


*/

  

E. Education

按人數從大到小考慮,每次選擇滿足條件的最便宜的房子。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5010;
int n,m,i,a[N],b[N],c[N],q[N],ans[N];
bool cmp(int x,int y){return a[x]<a[y];}
int ask(int x){
	int t=0,f=~0U>>1;
	for(int i=1;i<=m;i++)if(b[i]>=x){
		if(c[i]<f)f=c[i],t=i;
	}
	return t;
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",&a[i]),q[i]=i;
	for(i=1;i<=m;i++)scanf("%d",&b[i]);
	for(i=1;i<=m;i++)scanf("%d",&c[i]);
	sort(q+1,q+n+1,cmp);
	for(i=n;i;i--){
		int x=ask(a[q[i]]);
		if(!x)return puts("impossible"),0;
		b[x]=0;
		ans[q[i]]=x;
	}
	for(i=1;i<=n;i++)printf("%d ",ans[i]);
}

  

F. Flipping Coins

$f[i][j]$表示還需要操作$i$次,目前有$j$枚硬幣朝上時的最大期望正面向上的硬幣數。

時間複雜度$O(nk)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=444;
double f[N][N],ans;
int n,m,i,j;
int main(){
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)f[0][i]=i;
	for(i=1;i<=m;i++)for(j=0;j<=n;j++){
		if(j)f[i][j]=(f[i-1][j]+f[i-1][j-1])/2;
		if(j<n)f[i][j]=max(f[i][j],(f[i-1][j]+f[i-1][j+1])/2);
	}
	printf("%.10f",f[m][0]);
}

  

G. GentleBots

設估價函式為兩點到終點的曼哈頓距離之和,每次選取使得估價函式最優的方向走,若不能走,則隨機抖動。

#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int dx[7]={1,-1,0,0,0,0,0},
		  dy[7]={0,0,-1,1,0,0,0},
		  dz[7]={0,0,0,0,1,-1,0};
struct P{
	int x,y,z;
	void read(){
		scanf("%d%d%d",&x,&y,&z);
	}
	int dis(P b){
		return abs(x-b.x)+abs(y-b.y)+abs(z-b.z);
	}
	void write(){
		printf("(%d %d %d)",x,y,z);
	}
	P(){}
	P(int _x,int _y,int _z){x=_x,y=_y,z=_z;}
	P apply(int d){
		return P(x+dx[d],y+dy[d],z+dz[d]);
	}
}A,B,C,D;//A->B C->D
int main(){
	A.read();
	B.read();
	C.read();
	D.read();
	while(1){
		A.write();
		putchar(' ');
		C.write();
		puts("");
		int pre=A.dis(B)+C.dis(D);
		if(!pre)return 0;
		int best=~0U>>1;
		int I=0,J=0;
		for(int i=0;i<7;i++)for(int j=0;j<7;j++){
			P NA=A.apply(i),NC=C.apply(j);
			if(!NA.dis(C))continue;
			if(!NA.dis(NC))continue;
			if(!NC.dis(A))continue;
			if(!NC.dis(NA))continue;
			int now=NA.dis(B)+NC.dis(D);
			if(now<best)best=now,I=i,J=j;
		}
		if(best>=pre){
			while(1){
				int i=rand()%7,j=rand()%7;
				P NA=A.apply(i),NC=C.apply(j);
				if(!NA.dis(C))continue;
				if(!NA.dis(NC))continue;
				if(!NC.dis(A))continue;
				if(!NC.dis(NA))continue;
				I=i,J=j;
				break;
			}
		}
		A=A.apply(I);
		C=C.apply(J);
	}
}

  

H. Hiker Safety

能走就走,用佇列維護所有可能走的人,時間複雜度$O(n^2)$。

#include<cstdio>
const int N=10010;
int B,m,i,n,d[N],a[N],pos[N],r;
int h,t,x,q[10000000];
int cnt,fin[3333333];
inline int abs(int x){return x>0?x:-x;}
inline bool check(int x){
	if(pos[x]==m)return 0;
	int pre=x-1,nxt=x+1;
	if(nxt>r)nxt=0;
	if(pre){
		if(abs(d[pos[x]+1]-d[pos[pre]])>B)return 0;
		if(abs(d[pos[x]+1]-d[pos[pre]])<a[x])return 0;
		if(abs(d[pos[x]+1]-d[pos[pre]])<a[pre])return 0;
	}
	if(nxt){
		if(abs(d[pos[x]+1]-d[pos[nxt]])>B)return 0;
		if(abs(d[pos[x]+1]-d[pos[nxt]])<a[x])return 0;
		if(abs(d[pos[x]+1]-d[pos[nxt]])<a[nxt])return 0;
	}
	return 1;
}
inline void gao(int x){
	//printf("->%d\n",x);
	pos[x]++;
	fin[++cnt]=x;
	while(r&&pos[r]==m)r--;
	if(x>1)q[++t]=x-1;
	if(x<r)q[++t]=x+1;
	if(x<=r)q[++t]=x;
}
int main(){
	scanf("%d%d",&B,&m);
	for(i=1;i<=m;i++)scanf("%d",&d[i]);
	for(i=1;i<m;i++)if(d[i]>d[i+1])while(1);
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a[i],&pos[i]);
	}
	for(i=1;i<=n;i++){
		if(pos[i]<m)r=i;
	}
	//[1,r]
	h=1,t=0;
	for(i=1;i<=r;i++)q[++t]=i;
	while(h<=t){
		x=q[h++];
		if(check(x)){
			gao(x);
		}
	}
	for(i=1;i<=n;i++)if(pos[i]<m)return puts("impossible"),0;
	for(i=1;i<=cnt;i++)printf("%d ",fin[i]);
}

  

I. I Work All Day

按題意模擬即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
const int N = 3e5 + 10;
const int inf = 1e9;
int casenum, casei;
int c[15], e[15];
int n;
int main()
{
	while(~scanf("%d", &n))
	{
		for(int i = 0; i < n; ++i)scanf("%d", &c[i]);
		int T; scanf("%d", &T);
		int ans = c[0]; int val = T % c[0];
		for(int i = 1; i < n; ++i)
		{
			if(T % c[i] < val)
			{
				val = T % c[i];
				ans = c[i];
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
/*


*/

  

J. Just A Minim

按題意模擬即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
const int N = 3e5 + 10;
const int inf = 1e9;
int casenum, casei;
int c[2010], e[15];
int n;
int main()
{
	while(~scanf("%d", &n))
	{
		for(int i = 0; i < n; ++i)scanf("%d", &c[i]);
		double ans = 0;
		for(int i = 0; i < n; i ++){
			if(c[i] == 0) ans += 2;
			else if(c[i] == 1) ans += 1;
			else if(c[i] == 2) ans += 0.5;
			else if(c[i] == 4) ans += 0.25;
			else if(c[i] == 8) ans += 0.125;
			else if(c[i] == 16) ans += 0.0625;
		}
		printf("%.8f\n", ans);
	}
	return 0;
}
/*


*/

  

K. Knightsbridge Rises

拆點求最大流。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
const int N = 305, M = N * N * 8;
const int inf = 0x3f3f3f3f;
#define MS(x, y) memset(x, y, sizeof(x))
int n;
int L[N], W[N];
int ST, ED;
int first[N], ID;
int w[M], cap[M], nxt[M];
void ins(int x, int y, int cap_)
{
	w[++ID] = y;
	cap[ID] = cap_;
	nxt[ID] = first[x];
	first[x] = ID;
	
	w[++ID] = x;
	cap[ID] = 0;
	nxt[ID] = first[y];
	first[y] = ID;
}
int d[N];
bool bfs()
{
	MS(d, -1);
	queue<int>q; q.push(ST); d[ST] = 0;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		for(int z = first[x]; z; z = nxt[z])if(cap[z])
		{
			int y = w[z];
			if(d[y] == -1)
			{
				d[y] = d[x] + 1;
				q.push(y);
				if(y == ED)return 1;
			}
		}
	}
	return 0;
}
int dfs(int x, int all)
{
	if(x == ED)return all;
	int use = 0;
	for(int z = first[x]; z; z = nxt[z])if(cap[z])
	{
		int y = w[z];
		if(d[y] == d[x] + 1)
		{
			int tmp = dfs(y, min(cap[z], all - use));
			cap[z] -= tmp;
			cap[z ^ 1] += tmp;
			use += tmp;
			if(use == all)break;
		}
	}
	if(use == 0)d[x] = -1;
	return use;
}
int dinic()
{
	int ret = 0;
	while(bfs())ret += dfs(ST, inf);
	return ret;
}
vector<int>vt[N];
void go(int o, int x)
{	
	for(int z = first[x]; z; z = nxt[z])if((z & 1) && cap[z])
	{
		x = w[z];
		break;
	}
	if(x == 0)
	{
		//for(auto it : vt[o])
		/*
		int cnt = 0;
		for(int ii = 0; ii < vt[o].size(); ++ii)
		{
			int it = vt[o][ii];
			if(++cnt == 1)printf("%d", it);
			else printf(" %d", it);
		}
		puts("");
		*/
		return;
	}
	vt[o].push_back(x - n);
	go(o, x - n);
}
int main()
{
	while(~scanf("%d", &n))
	{
		MS(first, 0); ID = 1;
		ST = 0;
		for(int i = 1; i <= n; ++i)
		{
			scanf("%d%d", &W[i], &L[i]);
			if(W[i] == 0)
			{
				ins(ST, i, 1);
			}
			ins(i, n + i, 1);
		}
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 1; j <= n; ++j)if(j != i && L[i] >= W[j])
			{
				ins(n + i, j, 1);
			}
		}
		int m;
		scanf("%d", &m);
		ED = n + n + m + 1;
		for(int i = 1; i <= m; ++i)
		{
			int x;
			scanf("%d", &x);
			ins(n + n + i, ED, 1);
			for(int j = 1; j <= n; ++j)if(L[j] >= x)
			{
				ins(n + j, n + n + i, 1);
			}
		}
		if(dinic() != m)
		{
			puts("impossible");
		}
		else
		{
			for(int z = first[ED]; z; z = nxt[z])if((z & 1) && cap[z])
			{
				vt[w[z] - n - n].clear();
				go(w[z] - n - n, w[z]);
			}
			for(int o = 1; o <= m; ++o)
			{
				int cnt = 0;
				for(int ii = vt[o].size() - 1; ii >= 0; --ii)
				{
					int it = vt[o][ii];
					if(++cnt == 1)printf("%d", it);
					else printf(" %d", it);
				}
				puts("");
			}
		}
	}
	return 0;
}
/*
5
0 1
1 2
2 3
3 4
0 2
2
4 2

7
0 1
1 4
0 3
0 1
2 5
2 5
1 2
3
5 4 5

2
0 1
5 3
2
2 1

*/

  

L. Lounge Lizards

將所有點到原點的方向向量約分後分組,每組按距離從小到大排序,然後求LIS。

時間複雜度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
int n,i,j,k,m,f[N],ans;
struct P{int x,y,h;ll w;}a[N],O;
ll sqr(ll x){return x*x;}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline bool cmp(const P&a,const P&b){
	if(a.x!=b.x)return a.x<b.x;
	if(a.y!=b.y)return a.y<b.y;
	return a.w<b.w;
}
inline void ins(int x){
	if(!m||x>f[m]){
		f[++m]=x;
		return;
	}
	int l=1,r=m,mid,t;
	while(l<=r){
		mid=(l+r)>>1;
		if(f[mid]>=x)r=(t=mid)-1;else l=mid+1;
	}
	f[t]=x;
}
int main(){
	scanf("%d%d",&O.x,&O.y);
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].h);
		a[i].x-=O.x;
		a[i].y-=O.y;
		a[i].w=sqr(a[i].x)+sqr(a[i].y);
		//sgn gcd
		int d=gcd(abs(a[i].x),abs(a[i].y));
		a[i].x/=d,a[i].y/=d;
		//printf("%d %d %lld\n",a[i].x,a[i].y,a[i].w);
	}
	sort(a+1,a+n+1,cmp);
	for(i=1;i<=n;i=j){
		for(j=i;j<=n&&a[i].x==a[j].x&&a[i].y==a[j].y;j++);
		m=0;
		for(k=i;k<j;k++){
			ins(a[k].h);
		}
		ans+=m;
	}
	printf("%d",ans);
}
/*
0 0
6
0 -1 2
0 -2 2
0 -3 3
0 1 1
0 2 2
0 3 1
*/

  

相關文章