2014-02-12
■ SRM 526
Easy:
てきとうなぎにDuckを直線状に並べる問題。コストの最小化をする。
直線の候補を試していく。 必要なコストはソートして比較するだけで求められる。
//Bokan ga bokka--nn!! //Daily Lunch Special Tanoshii !! //これは、頭が悪く競プロが世界で一番できないHIR180が //IOI2014日本代表になるまでのN日間の記録である。 #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef pair<int,int> P; typedef pair<int,P> P1; typedef pair P2; typedef long long ll; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 2000000000 #define f first #define s second #define rep(i,x) for(int i=0;i
class DucksAlignment { public: int minimumTime(vector (int j=0;jgrid) { int n=grid.size(); int m=grid[0].size(); int tot=0; vector<int>x,y; for(int i=0;i for 'o'); if(grid[i][j]=='o') x.pb(i),y.pb(j); } } cout << x.size() << endl; sort(x.begin(),x.end()); sort(y.begin(),y.end()); int ret=INF; for(int i=0;i for(int j=0;j int sum=0; // tate if(i+tot-1>=n) goto nxt; for(int k=0;k for(int k=0;k nxt:; sum=0; // yoko if(j+tot-1>=m) continue; for(int k=0;k for(int k=0;k return ret; } };
Medium:
まず先手が勝つか後手が勝つか考える。
しかし、このルールだとどう見ても後手有利であり、先手が勝てる場合は相当限られる。
そもそも後手が勝てなくなる時は、素数が連続しているはずであり、そんなものは2と3しかない。
すなわち、先手の目標は後手に3つにして渡すことであるとわかる。
後手はその前に先手を潰しておかないといけないが、そのためには
先手が1~Kいずれをとっても合成数になるようにしないといけない。
つまり、1~Nのなかに合成数がK+1個以上連続している箇所があるか、N-1~N-Kが合成数であるかのいずれかが達成されないといけないし、達成されれば必ず後手が勝てる。
(前者は連続してるところの最大値の+1を渡された時に1個取ればよい、後者なら先手は何もできない)
これで先手後手のどちらが勝者になるか分かった。
(1) 先手勝ちのとき
先手は取れる範囲にある最小の素数をとればいいし、
後手はとれないなら終了、とれるなら自明に1個取ればよい。(2,3以外の素数-1は合成数だから)
(2)後手勝ちのとき
後手はもし取れる範囲で先手を潰せるなら潰す。そうでないなら最小の合成数をとる。
先手はとれないなら終了、とれるなら最大の素数をとる。
あとはこれをコードに起こすだけ。Nが極端に小さいのは埋め込んだほうが楽だし安全。
//Bokan ga bokka--nn!! //Daily Lunch Special Tanoshii !! //これは、頭が悪く競プロが世界で一番できないHIR180が //IOI2014日本代表になるまでのN日間の記録である。 #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef pair<int,int> P; typedef pair<int,P> P1; typedef pair P2; typedef long long ll; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 2000000000 #define f first #define s second #define rep(i,x) for(int i=0;i
bool notprime[500000]; int ret=0; class PrimeCompositeGame { public: int theOutcome(int N, int K) { if(N==1) return 0; if(N==2) return 0; if(N==3) return 1; if(N==4) return 1; notprime[1]=true; for(int i=2;i<=500000;i++) { if(notprime[i]) continue; for(int j=2;i*j<=500000;j++) { notprime[i*j]=true; } } int len=0; int max_interval=0,fi=-1; for(int i=N;i>=3;i--) { if(notprime[i]) len++; else { max_interval=max(max_interval,len); if(fi<0 && i!=N && !notprime[N]) fi=len; len=0; } } bool winner=((max_interval<=K) && (fi (winner) { int cur=N; int ret=0; while(1) { for(int i=max(3,cur-K);i<=cur-1;i++) { if(!notprime[i]) { cur=i; ret++; break; } } if(cur==3) return ret; while(!notprime[cur]) { cur--; } ret++; } } else { int cur=N; int ret=0; while(1) { int nxt=-1; for(int i=cur-1;i>=max(3,cur-K);i--) { if(!notprime[i]) { nxt=i; break; } } if(nxt==-1) return -1*ret; cur=nxt; ret++; nxt=-1; int len=0,kak=-1; for(int i=max(3,cur-K);i<=cur;i++) { if(!notprime[i]) { if(nxt==-1 && i-1>=cur-K && notprime[i-1]) { nxt=i-1; } if(len>=K+1) { kak=i-1; } len=0; } else { len++; } } ret++; if(kak>=0) cur=kak; else cur=nxt; } } } };if
DP解法?何それおいしいの?
■ Codeforces #229
絶望が生える
A: std:set
B: b[i]=1に気をつけて掛け算
C: 余りごとに累積和
E: 遅延評価segtreeやるだけ
D: このセット内ではダントツの難問。解法はやるだけ。嘘解法で突き進んで死んでしまいました。
Greedy苦手すぎる...