codeforces Rockethon 2015
2015-02-08 16:56:11
思路:大场!6500+人... (Orz.. 涨分降分都爽飞,TAT概率题好多)
Rank:911(rating:1853(-9)).... 这个rank让我想到了某恐怖袭击?...
改成了类似ACM的赛制,每个题目可能有多个测试点。只搞掉了A,B1,B2,G1....
C题逗比地推导了好久数学,搞了将近一个多小时- =,赛后想到了一种暴力Dfs... 就过了QAQ
反思:(1)比赛前放平心态,一个题目想好了再去敲,不然敲完再反复调试或频繁地换思路是很浪费时间的... (B1,B2各乱提交而wa一发是完全没有必要的)
(2)养成编程思维,不要一味地侧重数学,充分利用高速计算的特点,学会如何暴力枚举和Dfs非常重要!(就如C题)
A:简而言之就是两个不断扔石子,最优的扔法当然是每次扔一个,那么只要比较一下n1和n2即可。(ps:一开始没怎么懂题意,学弟提醒的^_^)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define REV(i,n) for(int i=(n-1);i>=0;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n1,n2,k1,k2; 28 29 int main(){ 30 scanf("%d%d%d%d",&n1,&n2,&k1,&k2); 31 if(n1 > n2) printf("First\n"); 32 else printf("Second\n"); 33 return 0; 34 }
B:这题没有考虑暴力骗B1的分,直接打了一发正解。首先考虑1的位置,显然要使 f(p) 最大,1要放在最两边(这样覆盖到1的区间数最少)。
然后考虑2的位置(排除了1),也是尽量放在两边...
于是我们知道每个数(最后一个数除外)有两个位置可放,那么使得 f(p) 最大的总方案数为 2^(n-1)。
然后就是类似康托展开的问题了。对于1,如果1放在首位,剩下的总方案数:2^(n-2),而1放在末尾的字典序必定大于1放在首位的字典序。那么判断m是否大于2^(n-2),如果大于,那么1放在末尾,且m -= 2^(n-2)。以此类推即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define REV(i,n) for(int i=(n-1);i>=0;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 ll n,m; 28 ll ans[1000]; 29 ll fac[1000]; 30 31 int main(){ 32 fac[0] = 1; 33 for(int i = 1; i <= 50; ++i) 34 fac[i] = fac[i - 1] * 2LL; 35 cin >> n >> m; 36 ll tmp = n; 37 ll p1 = 1,p2 = n; 38 for(int i = 1; i <= n; ++i){ 39 if(m > fac[n - i - 1]){ 40 m -= fac[n - i - 1]; 41 ans[p2--] = i; 42 } 43 else{ 44 ans[p1++] = i; 45 } 46 } 47 cout << ans[1]; 48 for(int i = 2; i <= tmp; ++i) 49 cout << " " << ans[i]; 50 cout << endl; 51 return 0; 52 }
C:这题... 看到别人普遍用bitmask枚举的... 本弱瞎搞了Dfs QAQ
1:首先记录下能取的竞拍价的最小值和最大值,然后枚举最后的second-price auction(设为t)是几。
2:然后枚举每个company出的竞拍价是大于 t,还是小于 t,还是等于 t。这个过程可以开个flag数组,用Dfs给每个company一个标记。
3:对于每个Dfs终点,我们获得了各个公司的竞拍价与 t 的关系,然后判断一下这组关系是否可行(因为要使最后的付款为 t)
4:对于所有可行关系组,我们就可以算出每个company与 t 产生该种关系的概率(如该公司:[4,7],t = 5 ,那么> t 的概率为 2/4),然后累加即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define REV(i,n) for(int i=(n-1);i>=0;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n,sc; 28 int L[10],R[10],len[10]; 29 int tmax = 0,tmin = INF; 30 int flag[10]; 31 double ans; 32 33 bool Judge(){ 34 FOR(i,1,n){ 35 if(flag[i] == 1 && L[i] >= sc) return false; 36 if(flag[i] == 2 && (sc < L[i] || sc > R[i])) return false; 37 if(flag[i] == 3 && R[i] <= sc) return false; 38 } 39 int c[10]; 40 MEM(c,0); 41 FOR(i,1,n) c[flag[i]]++; 42 if(c[2] >= 1 && (c[2] + c[3] >= 2) && c[3] <= 1) return true; 43 return false; 44 } 45 46 void Dfs(int p){ 47 if(p > n){ 48 if(Judge()){ 49 double p = 1.0; 50 FOR(i,1,n){ 51 if(flag[i] == 1) 52 p *= 1.0 * (min(R[i],sc - 1) - L[i] + 1) / len[i]; 53 else if(flag[i] == 2) 54 p /= (1.0 * len[i]); 55 else 56 p *= 1.0 * (R[i] - max(L[i],sc + 1) + 1) / len[i]; 57 } 58 ans += 1.0 * sc * p; 59 } 60 return; 61 } 62 FOR(i,1,3){ 63 flag[p] = i; 64 Dfs(p + 1); 65 } 66 } 67 68 int main(){ 69 scanf("%d",&n); 70 FOR(i,1,n){ 71 scanf("%d%d",&L[i],&R[i]); 72 tmax = max(tmax,R[i]); 73 tmin = min(tmin,L[i]); 74 len[i] = R[i] - L[i] + 1; 75 } 76 ll sum = 0; 77 for(sc = tmin; sc <= tmax; ++sc){ 78 MEM(flag,0); 79 Dfs(1); 80 } 81 printf("%.10f\n",ans); 82 return 0; 83 }
G1:没什么好的想法... 直接暴力Dfs枚举骗分了QAQ
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define REV(i,n) for(int i=(n-1);i>=0;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n,k; 28 int v[100]; 29 int v2[100]; 30 double ans; 31 double sum; 32 33 void Dfs(int s[100],int lev,double p){ 34 if(lev > k){ 35 //for(int i = 1; i <= n; ++i) printf("%d ",s[i]); 36 //puts(""); 37 int cnt = 0; 38 for(int i = 2; i <= n; ++i) 39 for(int j = 1; j < i; ++j) if(s[j] > s[i]) 40 cnt++; 41 ans += 1.0 * cnt * p; 42 return; 43 } 44 int ts[100]; 45 for(int i = 1; i <= n; ++i) ts[i] = s[i]; 46 for(int l = 1; l <= n; ++l){ 47 for(int r = l; r <= n; ++r){ 48 int mid = getmid(l,r); 49 for(int k = l; k <= mid; ++k) 50 swap(ts[k],ts[r - (k - l)]); 51 Dfs(ts,lev + 1,p / sum); 52 for(int i = 1; i <= n; ++i) ts[i] = s[i]; 53 } 54 } 55 } 56 57 58 int main(){ 59 scanf("%d%d",&n,&k); 60 FOR(i,1,n) scanf("%d",&v[i]); 61 sum = (n + 1) * n / 2; 62 Dfs(v,1,1.0); 63 printf("%.15f\n",ans); 64 return 0; 65 }
G2:递推想了半天... 虽然能看懂别人的代码... 但是自己想不到QAQ。
敲了一发暴力+记忆化。枚举数对(i,j)在k次操作后保持相对位置不变的概率P(Dfs实现),然后判断val[i]与val[j]的关系。
如果val[i] < val[j],那么ans += (1.0 - P)(原来顺序,要使产生逆序数,则要改变相对位置)
如果val[i] > val[j],那么ans += P
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 double ans,dp[205][35][35]; 28 int vis[205][35][35]; 29 int n,k,v[35],tot; 30 31 double Dfs(int l,int r,int m){ 32 if(vis[m][l][r]) 33 return dp[m][l][r]; 34 if(m == 0){ 35 if(l <= r) return 1.0; 36 return 0.0; 37 } 38 double res = 0.0; 39 REP(X,n) FOR(Y,X,n){ 40 int tl = l,tr = r; 41 if(X <= tl && tl <= Y) tl = X + Y - tl; 42 if(X <= tr && tr <= Y) tr = X + Y - tr; 43 res += Dfs(tl,tr,m - 1) / (double)tot; 44 } 45 vis[m][l][r] = 1; 46 return dp[m][l][r] = res; 47 } 48 49 int main(){ 50 MEM(vis,0); 51 scanf("%d%d",&n,&k); 52 REP(i,n) scanf("%d",v + i); 53 tot = n * (n + 1) / 2; 54 REP(i,n) FOR(j,i + 1,n){ 55 double res = Dfs(i,j,k); 56 if(v[i] < v[j]) ans += (1.0 - res); 57 else ans += res; 58 } 59 printf("%.15f\n",ans); 60 return 0; 61 }