2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017)
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 */