hosさんのXmas Contest 2012にPerorinCoders(りんごさん、きゅうり)で出て1位でした。
EとGを解いたのでコードをのせときます。
G
Ruins2と同じような方法でO(N^3)で出来る。
#include<cstdio> #include<cmath> #include<cstdlib> #include<algorithm> #define fi first #define se second #define rep(i,n) for(int i = 0; i < n; i++) #define rrep(i,n) for(int i = 1; i <= n; i++) using namespace std; typedef long long int ll; typedef pair<int,int> P; typedef pair<double,P> Q; const double eps = 1e-10; const int MX = 405, INF = 100000000; int n; int x[MX], y[MX]; ll dp[6][MX][MX]; Q e[MX*MX]; int ei; int main(){ int te; scanf("%d",&te); while(te--){ scanf("%d",&n); rep(i,n) scanf("%d%d",&x[i],&y[i]); rep(k,6)rep(i,n)rep(j,n) dp[k][i][j] = 0; ei = 0; rep(i,n){ dp[0][i][i] = 1; rep(j,n){ if(i == j) continue; e[ei++] = Q(atan2(x[j]-x[i],y[j]-y[i]),P(i,j)); } } sort(e,e+ei); int a, b; rep(i,ei){ a = e[i].se.fi; b = e[i].se.se; rep(k,5)rep(j,n) dp[k+1][j][b] += dp[k][j][a]; } ll ans = 0; rep(i,n) ans += dp[5][i][i]; printf("%lld\n",ans); } return 0; }
手元実行なので、O(N^4)でも間に合うらしく、ちょっと残念。
E
実行時間長くてもいいならいろいろ解き方あるっぽい?
まずは、強連結成分分解してDAGにして、exp+bonusとexpの最大値を両方計算していけば解ける。
#include<cstdio> #include<cstdlib> #include<algorithm> #define fi first #define se second #define rep(i,n) for(int i = 0; i < n; i++) #define rrep(i,n) for(int i = 1; i <= n; i++) using namespace std; typedef long long int ll; typedef pair<int,int> P; typedef pair<double,P> Q; const int MX = 300005, INF = 999999999; int n, m; bool bl[MX]; struct edge{ int next, to, c, d;}; edge e[MX], re[MX], ke[MX]; int head[MX], g; int rhead[MX], rg; int khead[MX], kg; bool used[MX]; int vn[MX], nv[MX], vk; bool kb[MX], kc[MX], kd[MX]; int dp1[MX], dp2[MX]; void dfs(int v){ if(used[v]) return; used[v] = true; for(int i = head[v]; i != -1; i = e[i].next) dfs(e[i].to); nv[vk--] = v; } void rdfs(int v){ if(!used[v]) return; used[v] = false; vn[v] = vk; for(int i = rhead[v]; i != -1; i = re[i].next) rdfs(re[i].to); } int main(){ int te, a, b, c, d, s, t; scanf("%d",&te); char ch; while(te--){ scanf("%d%d",&n,&m); rrep(i,n){ scanf(" %c",&ch); if(ch == '0') bl[i] = false; else bl[i] = true; head[i] = -1; rhead[i] = -1; khead[i] = -1; used[i] = false; kb[i] = kc[i] = kd[i] = false; } g = rg = kg = 0; rep(j,m){ scanf("%d%d%d%d",&a,&b,&c,&d); e[g] = (edge){head[a],b,c,d}; head[a] = g++; re[rg] = (edge){rhead[b],a,c,d}; rhead[b] = rg++; } vk = n; rrep(i,n) dfs(i); vk = 1; rrep(i,n){ if(!used[nv[i]]) continue; rdfs(nv[i]); vk++; } rrep(i,n){ a = vn[i]; if(bl[i]) kb[a] = true; for(int j = head[i]; j != -1; j = e[j].next){ b = vn[e[j].to]; if(a == b){ if(e[j].c) kc[a] = true; if(e[j].d) kd[a] = true; } else { ke[kg] = (edge){khead[a],b,e[j].c,e[j].d}; khead[a] = kg++; } } } s = vn[1]; t = vn[n]; //rrep(i,n) printf("%d ",nv[i]); //printf("%d %d\n",s,t); rrep(i,t){ dp1[i] = -INF; dp2[i] = -INF;} dp1[0] = 0; dp2[0] = 0; kc[0] = false; kd[0] = false; ke[kg] = (edge){-1,s,0,0}; khead[0] = kg++; for(int i = 0; i <= t; i++){ if(dp1[i] == -INF) continue; if(kc[i]) dp1[i] = dp2[i] = INF; if(kd[i]) dp1[i] = INF; if(kb[i]) dp2[i] = dp1[i]; for(int j = khead[i]; j != -1; j = ke[j].next){ b = ke[j].to; c = ke[j].c; d = ke[j].d; dp1[b] = min(max(dp1[b],dp1[i]+c+d),INF); dp2[b] = min(max(dp2[b],dp2[i]+c),INF); } } printf("%d\n",dp2[b]); } return 0; }
両方1発ACでうれしい。