Codeforces Round #243

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

时间: 2024-10-10 01:11:31

Codeforces Round #243的相关文章

Codeforces Round #243 (Div. 1)——Sereja and Two Sequences

题目链接 题意:给两个长度分别为n和m的序列,现在有两种操作:1.分别选择两个序列的一个非空前缀,切两个前缀的最后一位相同,删除之,得到1分(只累计),消耗e:2.直接删除两个序列,消耗值定于两个序列之前删除的元素个数之和,并且使得得到的分有效(之前没有有效分) 分析: 首先,问题其实就是转化成,进行若干次操作1,然后进行操作2 还要找到一个判别标准,来评判较优的状态(贪心) 每次的消耗值比较大,其实可以计算出最大的删除次数,这个值不是很大 状态表示: 简单的,一个状态可以表示为串A的位置.串B

Codeforces Round #243 (Div. 2) A. Sereja and Mugs

#include <iostream> #include <vector> #include <algorithm> #include <numeric> using namespace std; int main(){ int n,s; cin >> n >> s; vector<int> a(n); for(int i = 0 ; i < n ; ++ i) cin >> a[i]; sort(a.b

Codeforces Round #243 (Div. 2) B. Sereja and Mirroring

#include <iostream> #include <vector> #include <algorithm> using namespace std; int main(){ int n,m; cin >> n >> m; vector<vector<int> > a(n,vector<int>(m,0)); for(int i = 0; i < n; ++ i){ for(int j = 0 ;

Codeforces Round #243 (Div. 2) C. Sereja and Swaps

思路来源:http://blog.csdn.net/sf____/article/details/24626739 题目给出数据上限为200, 所以可以暴利所有区间. 解题思路: for i in range(n): for j in range(n): create priority_queue for w in range(k): if(Max.top > Min.top) SWAP(Max[element], Min[element]) 暴利枚举所有初始区间 [ i , j ] ,则剩下的

Codeforces Round #243 (Div. 2) C. Sereja and Swaps(优先队列 暴力)

题目 题意:求任意连续序列的最大值,这个连续序列可以和其他的 值交换k次,求最大值 思路:暴力枚举所有的连续序列.没做对是因为 首先没有认真读题,没看清交换,然后,以为是dp或者贪心 用了一下贪心,各种bug不对. 这次用了一下优先队列,以前用的不多,看这个博客又学了一下 AC代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #i

Codeforces Round #243 (Div. 1)

---恢复内容开始--- A 枚举l,r 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 us

Codeforces Round #243 (Div. 1) A题

http://codeforces.com/contest/425/problem/A 题目链接: 然后拿出这道题目是很多人不会分析题目,被题目吓坏了,其中包括我自己,想出复杂度,一下就出了啊!真是弱! 直接暴力求出矩阵数值,然后枚举每一个[I,J];再O[N]判断,分配好在[I,J]区间的数和之内的数,再排序下SOLO了 CODE:#include <cstdio> #include <cstring>#include <queue>#include <vect

Codeforces Round #243 (Div. 1)-A,B,C-D

这场CF真是逗了... 因为早上7点起的,所以到做CF的时候已经17个小时没有休息了,再加上中午5小时的比赛. 头脑很不清晰.做第一个题的时候差点读成求最大字段和了.然后发现是水体,迅速A掉. 然后开始看了B题,第一遍没有看懂,此时大脑已经看不下去了.然后突然某个群说D是水题. 我去看了一下D,我去,D的题意好简单啊....于是,冥思苦想中.....一直到快要1点 的时候,还是没有结果...此时我感觉不行了..要放弃D,于是,又去看B.仔细读了读题目, 才发现,B题才是真正的水题..一阵郁闷啊.

Codeforces Round #243 (Div. 2)——Sereja and Table

看这个问题之前,能够先看看这个论文<一类算法复合的方法>,说白了就是分类讨论,可是这个思想非常重要 题目链接 题意: 首先给出联通块的定义:对于相邻(上下和左右)的同样的数字视为一个联通块 现给一个n*m的仅仅有0和1的矩形和数字k,求出最小反转个数使得总体包含若干个矩形联通块(即每一个联通块均是矩形)(1?≤?n,?m?≤?100; 1?≤?k?≤?10) 假设最小次数比k大,输出-1 分析: 题目的特点是k比較小.也就是说反转的次数比較少,所以能够从这里入手.直接枚举全部的位置肯定是不行了