Codeforces Round #243 (Div. 1)

A. Sereja and Swaps

最简单的一道题,枚举所有区间[a,b],把[a,b]外最大的数与[a,b]中最小的数交换(最多交换k个),最后取最大的值

B. Sereja and Table

首先要明白,最后满足条件的矩阵一定满足如下条件:

存在一个基准行(或列),其余各行与它要么相同,要么完全相反。比如取第一行为基准行,对其余各行用数学归纳法就可以证明了。

剩下的工作就是要找到这样的基准行,方法很简单——枚举所有可能的基准行。如果有m列那么就有2^m种可能的基准行,m最大取100,肯定会超时。注意到k≤10,而且答案不超过k,考虑如下情况:

当m>k时,如果基准(注意这里以列为基准)不同于原来的任何一列(也不会和它完全相反,否则把基准列换为它),那么每一列都至少要变换一个数,也就是至少变换m>k个数,矛盾。于是在这种情况下基准列只能是原来m列中的某一列。

最后总结如下:

if (m > k) {
	//枚举每一列作为基准列 
	for (int i = 0; i < m; i++) {
		//code here
	}
}
else {
	//枚举所有可能的基准行
	//不超过2^m(m <= k <= 10)种
	//可以用二进制表示
	for (int i = 0; i < (1 << m); i++) {
		//code here
	}
}

完整代码如下:

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;

const int MAX_SIZE = 100 + 2;
const int INF = 100;
int a[MAX_SIZE][MAX_SIZE];

int main(int argc, char *argv[])
{
//	freopen("D:\\in.txt", "r", stdin);
	int n, m, k, i, j;
	cin >> n >> m >> k;
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			cin >> a[i][j];
		}
	}
	
	int ans = INF;
	if (m > k) {
		for (int base_col = 0; base_col < m; base_col++) {
			int tmp = 0;	//candidate answer
			for (j = 0; j < m; j++) {
				int cnt = 0;	//the number of different cells in column j
				for (i = 0; i < n; i++) {
					cnt += (a[i][j] != a[i][base_col]);
				}
				tmp += min(cnt, n - cnt);
			}
			ans = min(ans, tmp);
		}
	}
	else {
		for (int base_row = 0; base_row < (1 << m); base_row++) {
			int tmp = 0;
			for (i = 0; i < n; i++) {
				int cnt = 0;
				for (j = 0; j < m; j++) {
					cnt += ((base_row >> j) & 1) == a[i][j];
				}
				tmp += min(cnt, m - cnt);
			}
			ans = min(ans, tmp);
		}
	}
	
	if (ans > k) {
		ans = -1;
	}
	cout << ans << endl;
	
	return 0;
}

     
     
    
    
   
   

C. Sereja and Two Sequences

动态规划题目,多一个判断条件而已。

用dp[i][j]表示第j次执行1操作且删除的是a[i]时数列b删除的数的最小下标(即此时数列b删除b[dp[i][j]])。如果数列b中没有这样的数,那么dp[i][j] = INF。递推关系为:记 

f(k) = min{x | x > dp[k][j - 1] && b[x] == a[i]}

即第j - 1次删除a[k],第j次删除a[i]时数列b删除的数的最小下标,则

dp[i][j] = min{f(k)}(0 ≤ k < i)

最后判断满足能量关系就行了。

完整代码如下:

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          using namespace std; const int MAX_SIZE = 100000 + 2; int a[MAX_SIZE], b[MAX_SIZE]; int dp[MAX_SIZE]; vector 
         
           pos[MAX_SIZE]; int main(int argc, char *argv[]) { // freopen("D:\\in.txt", "r", stdin); int n, m, s, e, i, j; cin >> n >> m >> s >> e; for (i = 0; i < n; ++i) { scanf("%d", a + i); --a[i]; } for (i = 0; i < m; ++i) { scanf("%d", b + i); --b[i]; pos[b[i]].push_back(i); } for (i = 0; i < MAX_SIZE; i++) { pos[i].push_back(INT_MAX); } int cnt = s / e; int ans = 0; dp[0] = -1; for (i = 1; i <= cnt; ++i) { dp[i] = INT_MAX - 1; } for (i = 0; i < n; ++i) { for (j = cnt; j; --j) { dp[j] = min(dp[j], *upper_bound(pos[a[i]].begin(), pos[a[i]].end(), dp[j - 1])); if (dp[j] <= s - i - 2 - j * e && j > ans) { ans = j; } } } cout << ans << endl; return 0; } 
          
         
       
      
      
     
     
    
    
   
   

D. Sereja and Squares

用collx[i]存储x坐标为i的所有点的y坐标,用colly[i]存储y坐标为i的所有点的x坐标(相当于collx[i]表示直线x = i)。对于点P(x, y),搜寻以P为左下顶点的正方形,遍历直线collx[x]和colly[y]上的点,如果满足边长关系,再看是否存在第四个顶点(右上顶点)。

完整代码如下:

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          using namespace std; const int MAX_N = 100000 + 2; vector 
         
           collx[MAX_N], colly[MAX_N]; vector 
          
            ::iterator pos1, pos2, pos3; int main(int argc, char *argv[]) { int n, i, j; cin >> n; int maxx = 0, maxy = 0; for (i = 0; i < n; i++) { int x, y; scanf("%d%d", &x, &y); collx[x].push_back(y); colly[y].push_back(x); maxx = max(maxx, x); maxy = max(maxy, y); } for (i = 0; i <= maxx; i++) { sort(collx[i].begin(), collx[i].end()); } for (i = 0; i <= maxy; i++) { sort(colly[i].begin(), colly[i].end()); } int cnt = 0; for (i = 0; i <= maxx; i++) { for (pos1 = collx[i].begin(); pos1 != collx[i].end(); ++pos1) { int x = i, y = *pos1; pos2 = lower_bound(colly[y].begin(), colly[y].end(), x); pos3 = pos1 + 1; ++pos2; while (pos2 != colly[y].end() && pos3 != collx[x].end()) { if (*pos2 - x < *pos3 - y) { ++pos2; } else if (*pos2 - x > *pos3 - y) { ++pos3; } else { if (binary_search(collx[*pos2].begin(), collx[*pos2].end(), *pos3)) { ++cnt; } ++pos2; ++pos3; } } } } cout << cnt << endl; return 0; } 
           
          
         
       
      
      
     
     
    
    
   
   

E. Sereja and Sets

还在研究中。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值