2018 German Collegiate Programming Contest (GCPC 18)_组队训练
2018 German Collegiate Programming Contest (GCPC 18)
A Attack on Alpha-Zet
B Battle Royale
C Coolest Ski Route
D Down the Pyramid
E Expired License
F Fighting Monsters
H Hyper Illuminati
I It’s Time for a Montage
K Kitchen Cable Chaos
L Logic Puzzle
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 3030; char mp[maxn][maxn]; bool vis[maxn*maxn]; int n,m,q,dis[maxn*maxn],fa[3001000][25]; typedef pair<int,int> pp; vector<pp>v; vector<int>v2[maxn*maxn]; int getval(int x,int y) { return (x-1)*(m*2+1) + y*2; } void build_tree() { for(int i=2;i<=n+1;i++) { for(int j=2;j<=m*2;j+=2) { if(mp[i][j] == ' ') { v2[getval(i, j)].push_back(getval(i+1, j)); v2[getval(i+1, j)].push_back(getval(i, j)); } if(mp[i][j+1] != '|') { v2[getval(i, j)].push_back(getval(i, j+2)); v2[getval(i, j+2)].push_back(getval(i, j)); } } //cout<<i<<endl; } //cout<<1<<endl; } void dfs(int prev,int rt) { //cout<<prev<<endl; /*if(vis[prev] == 1) { return; } vis[prev] = 1;*/ dis[rt]=dis[prev]+1; fa[rt][0]=prev; for (int i=1;i<20;i++) fa[rt][i]=fa[fa[rt][i-1]][i-1]; for (int i=0;i<v2[rt].size();i++) { if(prev == v2[rt][i]) continue; dfs(rt, v2[rt][i]); } } int LCA(int x,int y) { //cout<<x<<endl; if (dis[x]<dis[y]) swap(x,y); for (int i=19;i>=0;i--) if (dis[x]-(1<<i)>=dis[y]) x=fa[x][i]; if (x==y) return x; for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main() { cin>>n>>m; getchar(); for(int i=1;i<=n+1;i++) { gets(mp[i]+1); //cout<<i<<endl; } //cout<<1<<endl; /*for(int i=1;i<=n+1;i++) { cout<<mp[i]+1<<endl; }*/ int q; cin>>q; for(int i=1;i<=q;i++) { int a,b; cin>>a>>b; v.push_back(make_pair(a,b)); } build_tree(); //cout<<1<<endl; int xx = getval(v[0].first+1, v[0].second*2); //cout<<xx<<endl; dfs(0, xx); ll ans = 0; for(int i=0;i<v.size()-1;i++) { int x = v[i].first; int y = v[i].second; int num1 = getval(x+1, y*2); x = v[i+1].first; y = v[i+1].second; int num2 = getval(x+1, y*2); ans += dis[num1] + dis[num2] - dis[LCA(num1, num2)] * 2; //cout<<i<<endl; } printf("%lld\n", ans); return 0; }
#include<bits/stdc++.h> #define ll long long int #define pi acos(-1.0) using namespace std; const double precision = 1e-7; int main() { double xc,yc,xd,yd,xb,yb,rb,xr,yr,rr; cin>>xc>>yc>>xd>>yd>>xb>>yb>>rb>>xr>>yr>>rr; if(xc==xd&&yc==yd) { puts("0.0000000"); return 0; } double d = 0; if(xd == xc&&yc != yd) { d = abs(xc-xr); } else{ d = fabs((yd-yc)*1.0/(xd-xc)*(xr-xc)+yc-yr)/(sqrt((yd-yc)*(yd-yc)*1.0/(xd-xc)/(xd-xc)+1)); } //cout<<d<<endl; double xx; if(d>=rr) { xx = sqrt((yc-yd)*(yc-yd)+(xc-xd)*(xc-xd)); printf("%.7lf",xx); } else{ double x1 = sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr)-rr*rr); double x2 = sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)-rr*rr); //cout<<x1<<" "<<x2<<endl; double xx1 = asin(rr/(sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr)))); double xx2 = asin(rr/(sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)))); //cout<<xx1<<" "<<xx2<<endl; xx1 = pi/2 - xx1; xx2 = pi/2 - xx2; double A = acos(((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr)+(xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)-((yc-yd)*(yc-yd)+(xc-xd)*(xc-xd)))/(2*sqrt((xd-xr)*(xd-xr)+(yd-yr)*(yd-yr))*sqrt((xc-xr)*(xc-xr)+(yc-yr)*(yc-yr)))); double B = A - xx1 - xx2; //cout<<B<<endl; double pp = B*rr; //cout<<pp<<endl; printf("%.7lf\n",pp+x1+x2); } }
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; vector<int>v[1010]; int mp[1010][1010]; int dist[1010]; bool vis[1010]; int n,m; int dfs(int step) { if(vis[step]) return dist[step]; for(int i=0;i<v[step].size();i++) { dist[step]=max(dist[step],dfs(v[step][i])+mp[step][v[step][i]]); } vis[step] = 1; return dist[step]; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int s,t,c; cin>>s>>t>>c; v[s].push_back(t); mp[s][t] = max(mp[s][t],c); } int maxx = 0; for(int i=1;i<=n;i++) { maxx = max(maxx,dfs(i)); } cout<<maxx<<endl; }
D Down the Pyramid
题意:给你一个数字金字塔,金子塔上的数字为下面左下和右下的两数之和,现在给你一排金字塔的数,求下面一排金字塔的数可以有多少种。
题解:我们可以把下一行金字塔的第一个定为0,然后求出符合规则的这一行,因为我们知道这一行1,3,5,7......位如果增加1的话,2,4,6,8...位就会减少1
所以为了满组所有最小为0,那么我们看一下1,3,5,7...位最小需要加多少才可以到达0,而2,4,6,8....最多可以减多少到达0,他们的差值就是了。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; ll a[1001000]; ll b[1000100]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } b[1] = 0; int ans = 2; for(int i=1;i<=n;i++) { b[ans] = a[i] - b[ans-1]; ans++; } /*for(int i=1;i<ans;i++) { cout<<b[i]<<" "; } cout<<endl;*/ ll minn = 0; for(int i=1;i<ans;i+=2) { if(b[i]<0) { minn = min(minn,b[i]); } } minn = -minn; //cout<<minn<<endl; ll maxx = 10000000000; for(int i=2;i<ans;i+=2) { if(b[i]-minn<0) { puts("0"); return 0; } else{ maxx = min(maxx,b[i]-minn+1); } } cout<<maxx<<endl; }
E Expired License
题意:给你两个实数比看你能不能转化位两个质数比,实数最多为小数点后5位.
题解:将输入以字符串输入,然后将他们扩大100000倍,求个gcd,一开始用欧拉筛初始化一下,然后判定一下,不过当两个数一样的时候判定一下输出2 2
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 1e7+5; int prime[maxn]; int visit[maxn]; void Prime(){ mem(visit,0); mem(prime, 0); for (int i = 2;i <= maxn; i++) { //cout<<" i = "<<i<<endl; if (!visit[i]) { prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数 } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) { // cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl; visit[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } } } ll change(string s) { int len = s.length(); int k = len; ll xx = 0; for(int i=0;i<len;i++) { if(s[i]=='.') { k=i; break; } xx=xx*10+s[i]-'0'; } ll yy = 0; int ans = 10000; for(int i=k+1;i<len;i++) { yy +=(s[i]-'0')*ans; ans/=10; } return xx*100000+yy; } int main() { int T; Prime(); cin>>T; while(T--) { string a,b; cin>>a>>b; ll x = change(a); ll y = change(b); //cout<<x<<" "<<y<<endl; ll ans = __gcd(x,y); ll c = x/ans; ll d = y/ans; if(c==d){ cout<<2<<" "<<2<<endl; continue; } if(visit[c]==0&&visit[d]==0&&c!=1&&d!=1) { cout<<c<<" "<<d<<endl; } else{ puts("impossible"); } } }
Problem F: Fighting Monsters
题意:让你在一个数组里找到可以最后减为一个0,一个1的两个数。
题解:由这个性质可以得出最后的两个数为0,1.。。。1,1。。。。1,2.。。。。3.,2。。。3,5,看你看出得到的为两个连续斐波那契数,所以在数组中找就可以
了。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; ll a[1001000]; ll b[1000100]; map<int,int>mp; map<int,int>mm; map<int,int>mo; int f[1000100]; int main() { int n; cin>>n; int ans = 0; for(int i=1;i<=n;i++) { cin>>a[i]; mo[a[i]] = i; if(a[i]==1) ans++; b[i] = a[i]; } //sort(a+1,a+1+n); if(ans>=2) { int q = 0; for(int i=1;i<=n;i++) { if(a[i]==1) { cout<<i<<" "; q++; } if(q>=2) break; } return 0; } bool flag = 0; f[1] = 1; f[0] = 1; mp[1] = 1; mm[1] = 0; for(int i=2;i<10000;i++) { f[i] = f[i-1] + f[i-2]; mp[f[i]] = 1; mm[f[i]] = f[i-1]; if(f[i]>1000000) { break; } } for(int i=1;i<=n;i++) { if(mp[a[i]]&&mo[mm[a[i]]]) { //cout<<mm[a[i]]<<endl; if(a[i]<a[mo[mm[a[i]]]]) cout<<i<<" "<<mo[mm[a[i]]]<<endl; else{ cout<<mo[mm[a[i]]]<<" "<<i<<endl; } flag = 1; break; } } if(!flag) puts("impossible"); }
H Hyper Illuminati
题意:给你一给数字为小方块的总个数,让你求可不可以构成n维s层的金字塔堆。
题解:由于数字不大,所以暴力枚举就可以了,满足∑ si=1 in-1== m。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 3030; long long modexp(long long a, long long b) { long long res=1; while(b>0) { if(b&1) res=res*a; b=b>>1; a=a*a; } return res; } int main() { ll m; cin>>m; for(int i=3;i<=60;i++) { ll sum = 0; for(int j=1;;j++) { sum += modexp(j,i-1); if(sum == m) { cout<<i<<" "<<j; return 0; } else if(sum>m) { break; } } } puts("impossible"); }
I It’s Time for a Montage
题解:有n个士兵和n个敌人,每个人都有一个力量值,你的人训练一天可以增加一点力量,打仗是这样的:按顺序从1到n,a[i]打b[i],只要a[i]>b[i],你就赢了,a[i]<b[i],你就输了,相等就看下一个,全部相等也算你赢,问你最少要训练几天才可以打败对方。
题解:可以枚举天数,因为数字不大,直接暴力枚举就行。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 1010; const ll mod = 1000000009; int h[1010],v[1001],d[1010]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>h[i]; } for(int i=1;i<=n;i++) { cin>>v[i]; } for(int i=1;i<=n;i++) { d[i] = h[i]-v[i]; } for(int i=0;i<=1001;i++) { for(int j=1;j<=n;j++) { d[j]+=i; } int ans = 0; bool flag = 0; for(int j=1;j<=n;j++) { if(d[j]<0) { break; } if(d[j]>0) { flag = 1; break; } if(d[j]==0) { ans++; } } if(ans == n) { flag = 1; } if(flag) { printf("%d\n",i); return 0; } for(int j=1;j<=n;j++) { d[j] -= i; } } }
L Logic Puzzle
题意:扫雷图复原。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 1010; const ll mod = 1000000009; int mp[120][120]; int ans[120][120]; int main() { int n,m; cin>>n>>m; for(int i=1; i<=n+2; i++) { for(int j=1; j<=m+2; j++) { cin>>mp[i][j]; } } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(mp[i][j]>0) { ans[i][j]=1; mp[i][j+1]--;mp[i][j]--;mp[i][j+2]--;mp[i+1][j+1]--;mp[i+1][j+2]--; mp[i+1][j]--;mp[i+2][j+1]--;mp[i+2][j+2]--;mp[i+2][j]--; } else if(mp[i][j]<0) { puts("impossible"); return 0; } } for(int k=1; k<=m+2; k++) { if(mp[i][k]!=0) { puts("impossible"); return 0; } } } for(int i=n; i<=n+2; i++) { for(int j=1; j<=m+2;j++) { if(mp[i][j]!=0) { puts("impossible"); return 0; } } } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(ans[i][j]==1) printf("X"); else printf("."); } cout<<endl; } return 0; }