CF 1393

CF Round #622

A

题意:n*n的网格,外框被激活。A/B两人轮流激活格子,激活一个格子的条件:四联通的位置有格子激活,四联通的位置没有同色的格子。
思路:输出n/2+1即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
int main()
{
	int T;
	scanf("%d",&T);
	while(T)
	{
		T--;
		int n;
		scanf("%d", &n);
		printf("%d\n",n/2 + 1);
	}
	return 0;
}

B

题意:插入/删除一些木棍,询问这些木棍是否可以组成一个正方形和一个长方形。
思路:统计每种长度有多少根+一堆特判。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define LL long long
using namespace std;
set<int>quemax,quemin;
set<int>:: iterator it;
const int N = 1e5 + 10;
const int maxn = 1e5;
int a[N];
int main()
{
	int n, x, m;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
	{
		scanf("%d",&x);
		a[x]++;
	}
	for(int i = 1; i <= maxn; i++)
	{
		if(a[i] >= 4)	quemax.insert(i);
		if(a[i] >=2 &&a[i] <= 3)	quemin.insert(i);
	}
	scanf("%d",&m);
	for(int i = 1; i <= m; i++)
	{
		int flag = 0;
		char s[10];
		scanf("%s",s);
		scanf("%d",&x);
		if(s[0]=='+')
		{
			a[x]++;
			if(a[x] == 2)	quemin.insert(x);
			if(a[x] == 4){
				quemin.erase(x);
				quemax.insert(x);
			}
		}
		else
		{
			a[x]--;
			if(a[x] == 3)
			{
				quemax.erase(x);
				quemin.insert(x);
			}
			if(a[x] == 1)
			{
				quemin.erase(x);
			}
		}
		if(quemax.size()>=2)
		{
			flag = 1;
		}
		else
		{
			if(quemax.size())
			{
				it = quemax.begin();
				x = *it;
				int t = a[x] - 4;
				if(t >= 4)
					flag = 1;
				if(t>=2 && quemin.size()>=1)
					flag = 1;
				if(quemin.size()>=2)
					flag = 1;
			}
		}
		if(flag)
			printf("YES\n");
		else
			printf("NO\n"); 
	}
	return 0;
}

C

题意:构造一个排列,使得相同的数的间隔尽量大,输出最小间隔的最大值。
思路:统计出哪些数是众数,设a,b,c为众数(也可能有更多),x为其他的数,构造方法为abcxxxxxabcxxxxxabcxxxxxabc。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define LL long long
using namespace std;
const int N = 1e5 + 10;
int a[N];
int main()
{
	int T, n;
	scanf("%d", &T);
	while(T)
	{
		T--;
		scanf("%d", &n);
		for(int i = 1; i <= n; i++)
			a[i] = 0;
		int x;
		for(int i = 1; i <= n; i++)
		{
			scanf("%d", &x);
			a[x]++;
		} 
		int maxa = 0;
		for(int i = 1; i <= n; i++)
			maxa = max(maxa, a[i]);
		int cnt = 0, sum = 0;
		for(int i = 1; i <= n; i++)
		{
			if(a[i] == maxa)	cnt++;
			else	sum +=a[i];
		}
		int dist = cnt - 1 + sum / (maxa - 1);
		printf("%d\n",dist);
	}
	return 0;
}

D

题意:n*m网格,每个网格有不同的值,求同色的正方形(45度放置)的个数。
思路:将正方形切割成左右两个三角形,每个格子扫一遍,从左到右(从右到左)有单调性。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define LL long long
using namespace std;
const int N = 2e3 + 10;
int up[N][N], le[N][N], ri[N][N], dn[N][N], f[N][N];
char s[N][N];
int main()
{
	LL ans = 0;
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%s", s[i] + 1);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			up[i][j] = 1;
			le[i][j] = 1;
			if(s[i][j] == s[i - 1][j])
				up[i][j] = up[i - 1][j] + 1;
			if(s[i][j] == s[i][j - 1])
				le[i][j] = le[i][j - 1] + 1; 
		}
	}
	for(int i = n; i > 0;i--)
	{
		for(int j = m; j >0; j--)
		{
			dn[i][j] = 1;
			ri[i][j] = 1;
			if(s[i][j] == s[i + 1][j])
				dn[i][j] = dn[i + 1][j] + 1;
			if(s[i][j] == s[i][j + 1])
				ri[i][j] = ri[i][j + 1] + 1; 
		}
	}
	for(int i = 1; i <= n; i++)
	{
		int pre = 1;
		for(int j = 1; j <= m; j++)
		{
			if(j - pre + 1 > le[i][j])
				pre = j - le[i][j] + 1;
			if(j - pre + 1 > up[i][j])
				pre = j - up[i][j] + 1;
			if(j - pre + 1 > dn[i][j])
				pre = j - dn[i][j] + 1;
			f[i][j] = j - pre + 1;
		}
		pre = m;
		for(int j = m; j > 0; j--)
		{
			if(pre - j + 1 > ri[i][j])
				pre = j + ri[i][j] - 1;
			if(pre - j + 1 > up[i][j])
				pre = j + up[i][j] - 1;
			if(pre - j + 1 > dn[i][j])
				pre = j + dn[i][j] - 1;
			f[i][j] = min(f[i][j], pre - j + 1);
			ans += f[i][j];
		}
	}
	cout<<ans<<endl;
	return 0;
}

E

题意:n个串,每个串删一个字符或者不删,求n个串能排成按照字母序升序的方案的数量。
思路

  1. (串内)排序:求对于每一个串,求删除第i个字母后的串的排序。设 n x t i nxt_{i} nxti为第i个字母右侧第一个与之不同的字母的位置。从左到右扫一遍,如果 s i > s n x t i s_{i} > s_{nxt_{i}} si>snxti,放到sorted序列左边,否则放到右边。
  2. DP: f i , j f_{i,j} fi,j表示第i个串,删除第 s o r t e d j sorted_{j} sortedj位置的方案数。利用双指针法进行转移。
  3. 判断两个串的大小:hash+二分,二分第一个不同的位置,进行比较
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long 
using namespace std;
const int M = 1e6 + 1;
const int N = 1e5 + 1;
const LL base = 37;
const LL mod = 1e9 + 7; 
LL ff[M], h[2][M], f[2][M];
string str[N];
int nxt[2][M], sorted[2][M];
void get_sorted(int id)
{
	for(int i = str[id].size() - 1; i >= 0; i--)
	{
		if(str[id][i] != str[id][i + 1])	nxt[id % 2][i] = i + 1;
		else nxt[id % 2][i] = nxt[id % 2][i + 1];
	}
	h[id % 2][0] = str[id][0];
	for(int i = 1; i <= str[id].size(); i++)
		h[id % 2][i] = h[id % 2][i - 1] * base + str[id][i];
	int l = 0;
	int r = str[id].size() - 1;
	for(int i = 0; i < str[id].size(); i++)
	{
		if(str[id][i] > str[id][nxt[id % 2][i]])
		{
			sorted[id % 2][l] = i;
			l++;
		}
		else
		{
			sorted[id % 2][r] = i;
			r--;
		}
	}
	for(int i = str[id].size(); i > 0; i--)
	{
		if(sorted[id % 2][i - 1] != str[id].size() - 1)
			sorted[id % 2][i] = sorted[id % 2][i - 1];
		else
		{
			sorted[id % 2][i] = str[id].size();
			break;
		 } 
	}
}
LL get_hash(int x, int cx, int pos)
{
	if(pos < cx)
	{
		return h[x % 2][pos];
	}
	LL now = 0;
	if(cx > 0) now = h[ x % 2][cx - 1];
	now *= ff[pos + 1 - cx];
	now += h[x % 2][pos + 1] - ff[pos + 1 - cx] * h[x % 2][cx];   
	return now;
}
char get_c(int x, int cx, int pos)
{
	if(pos < cx)
		return str[x][pos];
	if(str[x].size() > pos + 1) return str[x][pos + 1];
	return 'a' - 1;
}
int check(int x, int cx, int y, int cy)
{
	int l = 0;
	int r = min(str[x].size(), str[y].size()) + 1;
	while(r - l > 1)
	{
		int mid = (l + r) >> 1;
		if(get_hash(x, cx, mid - 1) != get_hash(y, cy, mid - 1))
			r = mid;
		else
			l = mid;
	}
	if(get_c(x, cx, l) <= get_c(y, cy, l))
		return 1;
	return 0;
}
int main()
{
	ff[0] = 1;
	for(int i = 1; i <= 1e6; i++)	ff[i] = ff[i - 1] * base;
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		cin>>str[i];
	get_sorted(1);
	for(int i = 0; i <= str[1].size(); i++)
		f[1][i] = 1;
	for(int i = 2; i <= n; i++)
	{
		get_sorted(i);
		int k = 0;
		int x = sorted[(i - 1) % 2][k];
		LL sum = 0;
		for(int j = 0; j <= str[i].size(); j++)
		{
			int y = sorted[i % 2][j];
			while(k <= str[i - 1].size() && check(i - 1, x, i, y))
			{
				sum += f[(i - 1) % 2][k];
				if(sum >= mod)	sum -= mod;
				k++;
				x = sorted[(i - 1) % 2][k];
			}
			f[i % 2][j] = sum;
		 } 
	}
	LL ans = 0;
	for(int i = 0; i <= str[n].size(); i++)
	{
		ans += f[n % 2][i];
		if(ans >= mod)	ans -= mod;
	}
	cout<< ans;
	return 0;
} 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值