CF #277.5 div2
2014-11-20 22:41:06
总结:这场cf总共6题,比赛艹了四题,成功帮助绿名小号回蓝-。-‘,赛后补完。
A:问排序的交换方案,并输出,这种模拟题在cf不少见,就是比谁更暴力!
1 /************************************************************************* 2 > File Name: a.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Mon 17 Nov 2014 11:37:05 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int n; 28 int t[3010]; 29 int ans[3010][2],cnt; 30 31 int main(){ 32 scanf("%d",&n); 33 for(int i = 1; i <= n; ++i){ 34 scanf("%d",t + i); 35 } 36 37 for(int i = 1; i <= n; ++i){ 38 int tmin = INF,pos; 39 for(int j = i; j <= n; ++j){ 40 if(t[j] < tmin){ 41 tmin = t[j]; 42 pos = j; 43 } 44 } 45 if(pos != i){ 46 int tmp = t[i]; 47 t[i] = t[pos]; 48 t[pos] = tmp; 49 ans[++cnt][0] = i; 50 ans[cnt][1] = pos; 51 } 52 } 53 printf("%d\n",cnt); 54 for(int i = 1; i <= cnt; ++i){ 55 printf("%d %d\n",ans[i][0] - 1,ans[i][1] - 1); 56 } 57 return 0; 58 }
B:看似一道匹配题,比赛中第一反应就是排序贪心,其实想想就知道很好证明,能配则配肯定是最优解。
1 /************************************************************************* 2 > File Name: b.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Mon 17 Nov 2014 11:51:09 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int n,m; 28 int a[105],b[105]; 29 30 int main(){ 31 scanf("%d",&n); 32 for(int i = 1; i <= n; ++i) 33 scanf("%d",&a[i]); 34 scanf("%d",&m); 35 for(int i = 1; i <= m; ++i) 36 scanf("%d",&b[i]); 37 sort(a + 1,a + n + 1); 38 sort(b + 1,b + m + 1); 39 int vis[105]; 40 memset(vis,0,sizeof(vis)); 41 int ans = 0; 42 for(int i = 1; i <= n; ++i){ 43 for(int j = 1; j <= m; ++j){ 44 if(!vis[j] && abs(a[i] - b[j]) <= 1){ 45 vis[j] = 1; 46 ++ans; 47 break; 48 } 49 } 50 } 51 printf("%d\n",ans); 52 return 0; 53 }
C:贪心题,智商下线wa了几发,最后写了个无敌暴力的短程序。注意特判:s > 9m 和 s == 0 && m != 1 的情况
1 /************************************************************************* 2 > File Name: c.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Mon 17 Nov 2014 11:59:26 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int m,s; 28 int ans[105]; 29 int ans2[105]; 30 31 int main(){ 32 scanf("%d%d",&m,&s); 33 if(s > 9 * m){ 34 printf("-1 -1\n"); 35 return 0; 36 } 37 if(s == 0 && m != 1){ 38 printf("-1 -1\n"); 39 return 0; 40 } 41 int k = s; 42 for(int i = 1; i <= m; ++i){ 43 while(ans[i] < 9 && k > 0){ 44 ans[i]++; 45 --k; 46 } 47 } 48 ans2[1] = min(1,s); 49 k = s - 1; 50 for(int i = m; i >= 1; --i){ 51 while(ans2[i] < 9 && k > 0){ 52 ans2[i]++; 53 --k; 54 } 55 } 56 for(int i = 1; i <= m; ++i) printf("%d",ans2[i]); 57 printf(" "); 58 for(int i = 1; i <= m; ++i) printf("%d",ans[i]); 59 puts(""); 60 return 0; 61 }
D:搜索暴力题,比赛时花了5分钟看题意5分钟想思路,其实就是枚举每个点,然后从那个点出发,走两步(也就是Dfs深度为2),将走两步到的点的vis值加1,最后根据排列组合思想可知:设一个点作为走两步的终点被走到k次,那么当前枚举点和这个终点间形成k * (k - 1) / 2种菱形(除以二可以放在最后,以提高效率)
1 /************************************************************************* 2 > File Name: d.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Tue 18 Nov 2014 12:47:37 AM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const int maxn = 3010; 27 28 int n,m; 29 int first[maxn],next[maxn * 10],ver[maxn * 10],ecnt; 30 ll vis[maxn]; 31 32 void Init(){ 33 memset(first,-1,sizeof(first)); 34 ecnt = 0; 35 } 36 37 void Add_edge(int u,int v){ 38 next[++ecnt] = first[u]; 39 ver[ecnt] = v; 40 first[u] = ecnt; 41 } 42 43 void Dfs(int p,int dep){ 44 if(dep == 2){ 45 vis[p]++; 46 return; 47 } 48 for(int i = first[p]; i != -1; i = next[i]){ 49 int v = ver[i]; 50 Dfs(v,dep + 1); 51 } 52 } 53 54 int main(){ 55 Init(); 56 int a,b; 57 scanf("%d%d",&n,&m); 58 for(int i = 1; i <= m; ++i){ 59 scanf("%d%d",&a,&b); 60 Add_edge(a,b); 61 } 62 ll ans = 0; 63 for(int i = 1; i <= n; ++i){ 64 memset(vis,0,sizeof(vis)); 65 Dfs(i,0); 66 for(int j = 1; j <= n; ++j) if(i != j){ 67 ans += vis[j] * (vis[j] - 1); 68 } 69 } 70 printf("%I64d\n",ans / 2); 71 return 0; 72 } 73
E:01分数规划题,没接触过,比赛时看都没看,其实就是DP时用上分数规划,现在想想学过分数规划的基本都能A出来QAQ。
二分枚举 d[i] = a[i] - L * b[i] 中的L,然后就是普通O(n^2)的DP,注意DP过程中用的d[i]的值,然后判断终点dp[n]的DP值的正负再改变二分边界即可。
1 /************************************************************************* 2 > File Name: e.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Wed 19 Nov 2014 11:32:19 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const double eps = 1e-8; 27 28 int n; 29 double l,x[1010],b[1010]; 30 double dis[1010][1010]; 31 double dp[1010]; 32 int pre[1010],ans[1010]; 33 34 bool Check(double v){ 35 for(int i = 1; i <= n; ++i){ 36 dp[i] = INF; 37 for(int j = 0; j < i; ++j){ 38 double tmp = dp[j] + dis[j][i]; 39 if(tmp < dp[i]){ 40 dp[i] = tmp; 41 pre[i] = j; 42 } 43 } 44 dp[i] -= v * b[i]; 45 } 46 if(dp[n] <= 0) return true; 47 return false; 48 } 49 50 int main(){ 51 scanf("%d%lf",&n,&l); 52 for(int i = 1; i <= n; ++i){ 53 scanf("%lf%lf",x + i,b + i); 54 } 55 for(int i = 0; i <= n; ++i){ 56 for(int j = 0; j < i; ++j){ 57 dis[j][i] = sqrt(fabs(x[i] - x[j] - l)); 58 } 59 } 60 double low = 0,high = 1000.0; 61 while(fabs(high - low) > eps){ 62 double mid = getmid(low,high); 63 if(Check(mid)) 64 high = mid; 65 else 66 low = mid; 67 } 68 int pos = 0,p = n; 69 while(p){ 70 ans[++pos] = p; 71 p = pre[p]; 72 } 73 for(int i = pos; i >= 1; --i){ 74 if(i != pos) printf(" "); 75 printf("%d",ans[i]); 76 } 77 puts(""); 78 return 0; 79 }
F:就是个DP,cf果然是dp大户啊。。。从m+1行开始枚举到n行,一行放两个1,设dp[i][j]表示这一行还有i个列没有放过1,还有j个列只放了1个1。
方法1:挑两个i的列放,dp[i - 2][j + 2] += dp[i][j]
方法2:挑两个j的列放,dp[i][j - 2] += dp[i][j]
方法3:挑一个i的列,一个j的列放,dp[i - 1][j] += dp[i][j]
版本1:滚动数组,自己瞎搞的三维dp,530ms,慢到爆。
1 /************************************************************************* 2 > File Name: f.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Wed 19 Nov 2014 08:06:56 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int n,m; 28 char s[505]; 29 int num[505]; 30 ll mod,dp[2][505][505]; 31 32 int main(){ 33 scanf("%d%d%I64d",&n,&m,&mod); 34 for(int i = 1; i <= m; ++i){ 35 scanf("%s",s + 1); 36 for(int j = 1; j <= n; ++j){ 37 if(s[j] == '1') 38 num[j]++; 39 } 40 } 41 int c0 = 0,c1 = 0; 42 for(int j = 1; j <= n; ++j){ 43 if(num[j] == 0) ++c0; 44 else if(num[j] == 1) ++c1; 45 } 46 int now = 0; 47 dp[now][c0][c1] = 1; 48 for(int k = m; k < n; ++k){ 49 for(int i = 0; i <= n; ++i){ 50 for(int j = 0; j <= n; ++j){ 51 if(dp[now][i][j] == 0) 52 continue; 53 if(i >= 2) 54 dp[now ^ 1][i - 2][j + 2] = (dp[now ^ 1][i - 2][j + 2] + dp[now][i][j] * i * (i - 1) / 2) % mod; 55 if(j >= 2) 56 dp[now ^ 1][i][j - 2] = (dp[now ^ 1][i][j - 2] + dp[now][i][j] * j * (j - 1) / 2) % mod; 57 if(i >= 1 && j >= 1) 58 dp[now ^ 1][i - 1][j] = (dp[now ^ 1][i - 1][j] + dp[now][i][j] * i * j) % mod; 59 } 60 } 61 now ^= 1; 62 } 63 printf("%I64d\n",dp[now][0][0]); 64 return 0; 65 }
版本2:;利用i单调递减性优化到O(n^2)的,46ms,可以接受。
1 /************************************************************************* 2 > File Name: f.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Wed 19 Nov 2014 08:06:56 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int n,m; 28 char s[505]; 29 int num[505]; 30 ll mod,dp[505][505]; 31 32 int main(){ 33 scanf("%d%d%I64d",&n,&m,&mod); 34 for(int i = 1; i <= m; ++i){ 35 scanf("%s",s + 1); 36 for(int j = 1; j <= n; ++j){ 37 if(s[j] == '1') 38 num[j]++; 39 } 40 } 41 int c0 = 0,c1 = 0; 42 for(int j = 1; j <= n; ++j){ 43 if(num[j] == 0) ++c0; 44 else if(num[j] == 1) ++c1; 45 } 46 dp[c0][c1] = 1; 47 for(int i = n; i >= 0; --i){ 48 for(int j = n; j >= 0; --j){ 49 if(dp[i][j] == 0) 50 continue; 51 if(i >= 2) 52 dp[i - 2][j + 2] = (dp[i - 2][j + 2] + dp[i][j] * i * (i - 1) / 2) % mod; 53 if(j >= 2) 54 dp[i][j - 2] = (dp[i][j - 2] + dp[i][j] * j * (j - 1) / 2) % mod; 55 if(i >= 1 && j >= 1) 56 dp[i - 1][j] = (dp[i - 1][j] + dp[i][j] * i * j) % mod; 57 } 58 } 59 printf("%I64d\n",dp[0][0]); 60 return 0; 61 }