CF 243 DIV1 & DIV2
DIV2的A和B都太水,直接暴力搞就可以的。
DIV2A
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/30 19:42:51
4 File Name :E:\2014ACM\Codeforces\CF243\DIV2_A.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20
21 int a[110];
22 int main()
23 {
24 //freopen("in.txt","r",stdin);
25 //freopen("out.txt","w",stdout);
26 int n,s;
27 while(scanf("%d%d",&n,&s) == 2)
28 {
29 for(int i = 0;i < n;i++)
30 scanf("%d",&a[i]);
31 sort(a,a+n);
32 int ans = 0;
33 for(int i = 0;i < n-1;i++)
34 ans += a[i];
35 if(ans <= s)printf("YES\n");
36 else printf("NO\n");
37 }
38 return 0;
39 }
DIV2B
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/30 19:53:16
4 File Name :E:\2014ACM\Codeforces\CF243\DIV2_B.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20 const int MAXN = 110;
21 int a[MAXN][MAXN];
22 int b[MAXN][MAXN];
23
24 int main()
25 {
26 //freopen("in.txt","r",stdin);
27 //freopen("out.txt","w",stdout);
28 int n,m;
29 while(scanf("%d%d",&n,&m) == 2)
30 {
31 for(int i = 0;i < n;i++)
32 for(int j = 0;j < m;j++)
33 scanf("%d",&a[i][j]);
34 int tmp = n;
35 if(tmp%2)
36 {
37 printf("%d\n",n);
38 continue;
39 }
40 for(int i = 0;i < n;i++)
41 for(int j = i+1;j < n;j++)
42 {
43 int tt = 1;
44 for(int k = 0;k < m;k++)
45 if(a[i][k] != a[j][k])
46 {
47 tt = 0;
48 break;
49 }
50 b[i][j] = b[j][i] = tt;
51 }
52 for(int t = 1;t <= n;t++)
53 {
54 int tmp = t;
55 while(tmp < n)tmp *= 2;
56 if(tmp != n)continue;
57 bool flag = true;
58 int mir = t;
59 while(mir != n)
60 {
61 for(int i = 0;i < mir;i++)
62 if(b[i][2*mir-1-i] == 0)
63 {
64 flag = false;
65 break;
66 }
67 if(!flag)break;
68 mir *= 2;
69 }
70 if(flag)
71 {
72 printf("%d\n",t);
73 break;
74 }
75 }
76 }
77 return 0;
78 }
DIV1A
题意:
给出了n(1<=n<=200)的数列a,
让你最多交换k(1<=k<=10)次,使得最大连续子序列的和最大。输出最大的连续子序列和。
因为n比较小,直接暴力枚举区间,然后将这个区间的k个小的,换成比较大的。
代码君:
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/27 23:29:36
4 File Name :E:\2014ACM\Codeforces\CF243\A.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20
21 const int MAXN = 220;
22 int a[MAXN];
23 int b[MAXN];
24 int c[MAXN];
25 int main()
26 {
27 //freopen("in.txt","r",stdin);
28 //freopen("out.txt","w",stdout);
29 int n,k;
30 while(scanf("%d%d",&n,&k) == 2)
31 {
32 for(int i = 1;i <= n;i++)
33 scanf("%d",&a[i]);
34 int ans = -1000000000;
35 for(int l = 1;l <= n;l++)
36 for(int r = l;r<= n;r++)
37 {
38 int cnt1 = 0;
39 int cnt2 = 0;
40 for(int i = 1;i <= n;i++)
41 {
42 if(i >= l && i <= r)
43 b[cnt1++] = a[i];
44 else c[cnt2++] = a[i];
45 }
46 sort(b,b+cnt1);
47 sort(c,c+cnt2);
48 reverse(c,c+cnt2);
49 int tt = min(cnt1,cnt2);
50 tt = min(tt,k);
51 for(int i = 1;i < cnt1;i++)
52 b[i] += b[i-1];
53 for(int i = 1;i < cnt2;i++)
54 c[i] += c[i-1];
55
56
57 for(int i = 0;i <= tt;i++)
58 {
59 int num1 = i;
60 int num2 = i;
61 int tmp = b[cnt1-1];
62 if(num1 > 0)tmp -= b[num1-1];
63 if(num2 > 0)tmp += c[num2-1];
64 ans = max(ans,tmp);
65 }
66
67 }
68 printf("%d\n",ans);
69 }
70 return 0;
71 }
DIV1B
给出一个n*m的01矩阵, 让你最多改变k个里面的值(0变1,1变0), 使得0、1的连通分量是矩阵。输出最少步数
1?≤?n,?m?≤?100; 1?≤?k?≤?10
题解:
如果01连通分量是矩形,
那么矩形一定是这样的:
0101010
1010101
0101010
1010101
(上面的01代表子矩阵块)。
也就是每一行要么是相同,要么是相反的。
如果n>k, 肯定有一行是不能改变的,那么枚举这一行,然后其余的要么变相同,要么变相反,看最少的步数。
如果n<k ,那么可以枚举第一列的状态(2^k), 然后其余列变成和第一列相同或者相反。
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/29 11:30:04
4 File Name :E:\2014ACM\Codeforces\CF243\B.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20 const int MAXN = 110;
21 int a[MAXN][MAXN];
22
23 int main()
24 {
25 //freopen("in.txt","r",stdin);
26 //freopen("out.txt","w",stdout);
27 int n,m,k;
28 while(scanf("%d%d%d",&n,&m,&k) == 3)
29 {
30 for(int i = 0;i < n;i++)
31 for(int j = 0;j < m;j++)
32 scanf("%d",&a[i][j]);
33 int ans = 100000000;
34 if(n > k)
35 {
36 for(int t = 0;t < n;t++)
37 {
38 int tmp = 0;
39 for(int i = 0;i < n;i++)
40 {
41 int cnt = 0;
42 for(int j = 0;j < m;j++)
43 if(a[i][j] == a[t][j])
44 cnt++;
45 tmp += min(cnt,m-cnt);
46 }
47 ans = min(tmp,ans);
48 }
49 }
50 else
51 {
52 for(int t = 0;t < (1<<n);t++)
53 {
54 int tmp = 0;
55 for(int j = 0;j < m;j++)
56 {
57 int cnt = 0;
58 for(int i = 0;i < n;i++)
59 if(a[i][j] == ((t>>i)&1))
60 cnt++;
61 tmp += min(cnt,n-cnt);
62 }
63 ans = min(tmp,ans);
64 }
65 }
66 if(ans <= k)printf("%d\n",ans);
67 else printf("-1\n");
68 }
69 return 0;
70 }
DIV1C
题意:比较长,自己看题目吧
1?≤?s?≤?3·10^5; 10^3?≤?e?≤?10^4
所以第一个操作最多是300次.
用dp[i][j] 表示a序列消掉了前i个,消了j次,b序列的最小位置。
转移的时候,dp[i][j],
其实就是dp[0][j-1],dp[1][j-1],......dp[i-1][j-1]中最小的,下一个a[i]的位置。
用个数组标记下位置,因为那个最小值是递减的。
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/29 22:16:58
4 File Name :E:\2014ACM\Codeforces\CF243\C.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20
21 int dp[310][100010];
22 int a[100010];
23 int b[100010];
24 vector<int>vb[100010];
25 int next[100010];
26
27 int main()
28 {
29 //freopen("in.txt","r",stdin);
30 //freopen("out.txt","w",stdout);
31 int n,m,s,e;
32 while(scanf("%d%d%d%d",&n,&m,&s,&e) == 4)
33 {
34 for(int i = 0;i < n;i++)
35 scanf("%d",&a[i]);
36 for(int i = 0;i < m;i++)
37 scanf("%d",&b[i]);
38 for(int i = 1; i <= 100000;i++)
39 vb[i].clear();
40 for(int i = 0;i < m;i++)
41 vb[b[i]].push_back(i);
42 for(int i = 1; i <= 100000;i++)
43 vb[i].push_back(m);
44 int k = s/e;
45 int ans = 0;
46 for(int i = 1;i <= k;i++)
47 {
48 for(int j = 1;j <= 100000;j++)
49 next[j] = vb[j].size() - 1;
50 int mm = m;
51 if(i == 1)mm = -1;
52 for(int j = 0;j < n;j++)
53 {
54 while(next[a[j]] > 0 && vb[a[j]][next[a[j]]-1] > mm)
55 next[a[j]]--;
56 dp[i][j] = vb[a[j]][next[a[j]]];
57 if(i > 1)mm = min(mm,dp[i-1][j]);
58 if(dp[i][j] < m && j + dp[i][j] + 2 + e*i <= s)
59 ans = max(ans,i);
60 }
61 }
62 printf("%d\n",ans);
63 }
64 return 0;
65 }
DIV1D
题意,给了n个点, 让你求出有多少个平行于坐标轴的正方形,四个点都在给定的点上。
可以使用hash或者二分查找,快速判断一个点是不是存在。
枚举x坐标,如果x的个数<sqrt(n),
那么两重循环枚举这个x的点,确定边长,然后进行hash判断是不是存在。
如果x的个数>=sqrt(n),
那么枚举下所有的点,来确定下边长,然后进行hash判断
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/30 18:27:57
4 File Name :E:\2014ACM\Codeforces\CF243\D.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20
21 vector<int>vx[100010];
22 bool has(int x,int y)
23 {
24 if(x > 100000 || y > 100000 || x < 0 || y < 0)return false;
25 return binary_search(vx[x].begin(),vx[x].end(),y);
26 }
27 int main()
28 {
29 //freopen("in.txt","r",stdin);
30 //freopen("out.txt","w",stdout);
31 int n;
32 while(scanf("%d",&n) == 1)
33 {
34 for(int i = 0;i <= 100000;i++)
35 vx[i].clear();
36 int x,y;
37 for(int i = 0;i < n;i++)
38 {
39 scanf("%d%d",&x,&y);
40 vx[x].push_back(y);
41 }
42 for(int i = 0;i <= 100000;i++)
43 sort(vx[i].begin(),vx[i].end());
44 int ans = 0;
45 int bd = (int)sqrt(1.0*n);
46 for(int x = 0;x <= 100000;x++)
47 if(vx[x].size())
48 {
49 if(vx[x].size() < bd)
50 {
51 for(int i = 0;i < vx[x].size();i++)
52 for(int j = i+1;j < vx[x].size();j++)
53 {
54 int d = vx[x][j] - vx[x][i];
55 if(has(x+d,vx[x][i]) && has(x+d,vx[x][j]))
56 ans++;
57 }
58 }
59 else
60 {
61 for(int xx = x+1;xx <= 100000;xx++)
62 for(int i = 0;i < vx[xx].size();i++)
63 {
64 int yy = vx[xx][i];
65 int d = xx - x;
66 if(has(x,yy) && has(x,yy+d) && has(xx,yy+d))
67 ans++;
68 }
69 }
70 }
71 printf("%d\n",ans);
72 }
73 return 0;
74 }
DIV1E
经典的DP题
使用dp[i][j] 表示最多j个不相交区间,最靠左的j个不相交区间的最后一个区间位置是i.
如果dp[i][j] -> dp[ii][j+1]的话,2^( (ii-i)*i ) 这种是横跨的区间,可选可不选。
(ii-i)个区间是最少要选择一个的, 2^(ii-i)-1
然后就可以得出来了。
1 /* ***********************************************
2 Author :kuangbin
3 Created Time :2014/4/28 0:47:23
4 File Name :E:\2014ACM\Codeforces\CF243\E.cpp
5 ************************************************ */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <queue>
13 #include <set>
14 #include <map>
15 #include <string>
16 #include <math.h>
17 #include <stdlib.h>
18 #include <time.h>
19 using namespace std;
20 const int MOD = 1e9+7;
21 const int MAXN = 550;
22 int dp[MAXN][MAXN];//dp[i][j]表示有j个不相交区间,最左的最后一个区间的位置是i
23 void Add(int &a,int b)
24 {
25 a += b;
26 while(a >= MOD)a -= MOD;
27 }
28 int two[510*510];
29 int main()
30 {
31 //freopen("in.txt","r",stdin);
32 //freopen("out.txt","w",stdout);
33 int n,k;
34 two[0] = 1;
35 for(int i = 1;i <= 500*500;i++)
36 two[i] = 2*two[i-1]%MOD;
37 while(scanf("%d%d",&n,&k) == 2)
38 {
39 memset(dp,0,sizeof(dp));
40 dp[0][0] = 1;
41 for(int i = 0;i < n;i++)
42 for(int j = 0;j < k;j++)
43 if(dp[i][j])
44 {
45 for(int ii = i+1;ii <= n;ii++)
46 {
47 long long tmp = two[i*(ii - i)];
48 tmp = tmp*(two[ii-i]-1)%MOD;
49 Add(dp[ii][j+1],tmp*dp[i][j]%MOD);
50 }
51 }
52 int ans = 0;
53 for(int i = 0;i <= n;i++)
54 Add(ans,(long long)dp[i][k]*two[i*(n-i)]%MOD);
55 printf("%d\n",ans);
56 }
57 return 0;
58 }
Codeforces Round #243