2010-01-05
過去問マラソン(#7): SRM457 (きのうの欠席回)
過去問マラソン | |
移動中で(というかSRMをその時間にやるのを知らずにその時間に移動してて)参加できなかったのでPractice Roomにて...
Easy(250): TheTriangleBothDivs
- 表示されうる文字列パターンは24x60x19通りなので全部試すよ
- 215.87pt = 11'40'' 遅い...
- passed system test
#define rep(var,n) for(int var=0;var<(n);var++) class TheTriangleBothDivs { string disp; public: string tostr(int m){ char buf[6]; sprintf(buf, "%02d:%02d", m/60, m%60); return buf; } bool possible(string s){ rep(i,11){ if(disp[i]=='?') continue; if(disp[i]!=s[i]) return false; } return true; } string fix(string time) { disp = time; char buf[12]; priority_queue<int> pq; for(int z=-9;z<=9;z++){ for(int h=0;h<24;h++){ for(int m=0;m<60;m++){ sprintf(buf,"%02d:%02d GMT%c%d",h,m, z>=0?'+':'-', abs(z)); if (possible(buf)) { int t=((h-z)*60 + m + 1440)%1440; pq.push(-t); } } } } return tostr(-pq.top()); } };
Medium(500): TheHexagonsDivOne
- パターン数え上げ
- 2nで%n比較、ではなく、n個の数字でそれぞれにchiralityのようなものがあると考えて
- 隣り合っていなければ、(chiralityの異なる)同じ数字を2回使ってもよい
- とすると、7つの枠のなかに0ペア、1ペア、2ペア、3ペアの可能性
- それぞれのパターンをカウント
- sample caseが通れば(あとlong long的な問題がなければ)大丈夫な気が
- 181.86pt = 74'56'' 間に合ってない...
- passed system test
typedef long long ll; #define sz(a) int((a).size()) #define pb push_back #define FOR(var,from,to) for(int var=(from);var<=(to);var++) #define rep(var,n) for(int var=0;var<(n);var++) #define all(c) (c).begin(),(c).end() class TheHexagonsDivOne { public: long long count(int n) { if (n*2 < 7) return 0LL; // 7枠あるのです. ll N=n; // (ll)nみたいにキャストして使うのめんどくさいから ll cnt=0LL; // BEGIN CUT HERE // 0組 z+ 123456 // END CUT HERE if (n>=7) { // z, a,b,c,d,e,f ll p = N * (N-1) * (N-2) * (N-3) * (N-4) * (N-5) * (N-6); ll mag = 2*2*2*2*2*2*2; // z,a,b,c,d,e,f cnt += p*mag/6; } // BEGIN CUT HERE // 1組 z+ 1.1..., 1..1.. // END CUT HERE if (n>=6) { // z, 1, a,b,c,d ll p = N * (N-1) * (N-2) * (N-3) * (N-4) * (N-5); ll mag = 2*2*2*2*2; // z,a,b,c,d ll pat = 2 + 1; cnt += p*mag*pat; // 1 } // BEGIN CUT HERE // 2組 z+ 1212.. // 121.2. // 121..2 // 12.21. 1.12.2 (=21.12.) // [13][24] [31][42] // 12.12. // 12.1.2(=212.1.=121.2.) // 1[24] 3[42] // //1.212.(=121.2.) //1.21.2(=21.21.) // END CUT HERE if (n>=5) { // z, 1,2, a,b ll p = N * (N-1) * (N-2) * (N-3) * (N-4); ll mag = 2*2*2; ll pat = 2*2 + 2*2 + 1*2 + 1*2; cnt += p*mag*pat; // 1,2 } // BEGIN CUT HERE // 3組 z + 121323, 131232, 123132 (132123), 123123, 132132, x // END CUT HERE if (n>=4) { // z, 1,2,3 ll p = N * (N-1) * (N-2) * (N-3); ll mag = 2; ll pat = 2*2*2 + 2*2*2 + 2*2*2 + 1*2*2 + 1*2*2; cnt += p*mag*pat/6; } return cnt; } };
cafelierさんのを見たら、パターンを頭つかって考えるのは良くないなあと思い書き直してみた。
#define rep(var,n) for(int var=0;var<(n);var++) #define all(c) (c).begin(),(c).end() long long c(int n, int r) { if (n == 0 || r == 0 || r == n) return 1LL; if (r > n-r) r = n-r; return c(n-1,r-1) * n / r; } class TheHexagonsDivOne { // 最小要素が[0]に来るようにvecを左にローテート vector<int> shift(vector<int> vec){ vector<int> res(sz(vec)); int at = min_element(all(vec)) - vec.begin(); rep(i,6) res[i] = vec[(at+i)%6]; return res; } public: long long count(int n) { if (n<4) return 0LL; ll N=(ll)n; ll cnt=0LL; // 3 pairs if (N >= 4) { vector<int> iota(6); iota[0]=-3, iota[1]=-2, iota[2]=-1, iota[3]=1, iota[4]=2, iota[5]=3; // 空き位置なし sort(all(iota)); set<vector<int> > pats; do { rep(i,6) if (abs(iota[i%6])==abs(iota[(i+1)%6])) goto next3; pats.insert( shift(iota) ); next3:; } while (next_permutation(all(iota))); cnt += c(N,4) * c(4,1)*2 * pats.size(); // c(N,4): N個の数から4つを選ぶ // c(4,1)*2: 4つのうち1つを中心に。左右あり // pats.size(): 残り3つの全順列 } // 2 pairs (z, 1,1,2,2,a,b) if (N >= 5) { vector<int> iota(6); iota[0]=-2, iota[1]=-1, iota[2]=1, iota[3]=2, iota[4]=0, iota[5]=0; // 空き位置2つ sort(all(iota)); set<vector<int> > pats; do { rep(i,6) { if (!iota[i]) continue; if (abs(iota[i%6])==abs(iota[(i+1)%6])) goto next2; } pats.insert( shift(iota) ); next2:; } while (next_permutation(all(iota))); cnt += c(N,5) * c(5,1)*2 * c(4,1)*2 * c(3,1)*2 * pats.size(); // c(N,5): N個の数から5つを選ぶ // c(5,1)*2: 5つのうち1つを中心に。左右あり // c(4,1)*2: 残り4つのうち1つを空き位置#1に。左右あり。 // c(3,1)*2: 残り3つのうち1つを空き位置#2に。左右あり。 // pats.size(): 残り2つの全順列。回転させて同じになるかは考慮済み。 } // 1 pair (z, 1,1,a,b,c,d) if (N >= 6) { vector<int> iota(6); iota[0]=-1, iota[1]=1, iota[2]=0, iota[3]=0, iota[4]=0, iota[5]=0; // 空き位置4つ sort(all(iota)); set<vector<int> > pats; do { rep(i,6) { if (!iota[i]) continue; if (abs(iota[i%6])==abs(iota[(i+1)%6])) goto next1; } pats.insert( shift(iota) ); next1:; } while (next_permutation(all(iota))); cnt += c(N,6) * c(6,1)*2 * c(5,1)*2 * c(4,1)*2 * c(3,1)*2 * c(2,1)*2 * pats.size(); // c(N,6): N個の数から6つを選ぶ // c(6,1)*2: 6つのうち1つを中心に。左右あり // c(5,1)*2: 残り5つのうち1つを空き位置#1に。左右あり。 // c(4,1)*2: 残り4つのうち1つを空き位置#2に。左右あり。 // c(3,1)*2: 残り3つのうち1つを空き位置#3に。左右あり。 // c(2,1)*2: 残り2つのうち1つを空き位置#1に。左右あり。 // pats.size(): 残り1つの全順列。回転させて同じになるかは考慮済み。 } // no pairs if (N >= 7) { cnt += c(N,7) * c(7,1)*2 * c(6,1)*2 * c(5,1)*2 * c(4,1)*2 * c(3,1)*2 * c(2,1)*2 * c(1,1)*2 / 6; // c(N,7): N個の数から7つを選ぶ // c(7,1)*2: 6つのうち1つを中心に。左右あり // c(6,1)*2: 残り6つのうち1つを空き位置#1に。左右あり。 // c(5,1)*2: 残り5つのうち1つを空き位置#2に。左右あり。 // c(4,1)*2: 残り4つのうち1つを空き位置#3に。左右あり。 // c(3,1)*2: 残り3つのうち1つを空き位置#4に。左右あり。 // c(2,1)*2: 残り2つのうち1つを空き位置#5に。左右あり。 // c(1,1)*2: 残り1つのうち1つを空き位置#6に。左右あり。 // /6: 回転させて同じになるやつをまとめる } return cnt; } };