Educational Codeforces Round 123 (Rated for Div. 2)

A:给6个字符串其中rgb和RGB各一个,分别代表钥匙和门,人从左往右走能不能走到尽头

题解:模拟,然后wa了,然后发现是if的时候R写成B了,傻逼玩意儿

B:构造序列,满足用到1-n的每个元素各一次且序列满足ai+ ai+1 !=ai+2(斐波那契)

题解:以9和8为例

8:8 1 / 7 2 / 6 3 / 5 4,两两一组,和为9,且大的数字在前,每组间隔的位置和为n(此时因为最大数n前面必为另外一组,和为n+1),头尾相连,相邻和为2*n+n/2,从中间切一刀,必然满足

9:9/8 1 / 7 2 / 6 3 / 5 4,最大数字放首位,不动,后面按照n-1处理,此时还差一个序列,n和n-1调换,后面不变,输出即可

另外的构造方法:以6为例,654321,将1往前提即可(好的我承认我是傻逼)

C:给一个数组,和一个数字x,f(k)表示给k个不同的位置+ x,加完后子串和最大,求k从0-n时子串和最大值

题解:对于一个k,和最大的结果的长度a可能比k大也可能比k小,如果比k小,结果就是sum(r-l+1)+(r-l+1)*x,比k大就是sum(r-l+1)+k*x

f1(i)表示长度为i的段,sum(i)+i*x的最大值

f2(i)表示长度为i的段,sum(i)+k*x的最大值

取k为j,则结果应该为f1从1-j的最大值,f2从j到n的最大值,的最大值

因此分别求一个前缀最大值和一个后缀最大值

而sum通过暴力来求出

#include<iostream>using namespace std;const int N = 5005;int sum[N];int a[N];int f[N];int q[N], h[N];int main(){int _, n, x;cin >> _;while (_--){cin >> n >> x;memset(sum, 0, sizeof(sum));memset(a, 0, sizeof(a));for (int i = 1; i <= n + 5; i++){f[i] = -0x7fffffff;//有的傻逼因为这里多写了个fwa了 h[i] = -0x7fffffff;//因为结果可能为负数,所以初始化的时候应该为最小值而不是0; }memset(q, 0, sizeof(q));for (int i = 1; i <= n; i++)cin >> a[i];//输入 for (int i = 1; i <= n; i++)sum[i] = sum[i - 1] + a[i];//前缀和,用来求线段和for (int i = 1; i <= n; i++)for (int j = 1; j + i - 1 <= n; j++)f[j] = max(f[j], sum[j + i - 1] - sum[i - 1]);//求长度为j的线段最大值for (int i = 1; i <= n; i++)q[i] = max(q[i - 1], f[i] + i * x);//f1,前缀最大值 for (int i = n; i >= 0; i--)h[i] = max(h[i + 1], f[i]);//f2,后缀最大值,少一个+k*x for (int i = 0; i <= n; i++)cout << max(h[i] + i * x, q[i]) << " ";cout << "
";}}

D:有一个n*m的表格,格子内初始为白。对表格有q个操作,每次操作在x行y列选择1-k中的某种颜色并染色,会把之前的颜色覆盖掉,问最后有多少种不同的方案数

题解:有点类似于上海站的割草问题,因为正向会重复计算所以直接反向,我们倒序模拟操作,并假设现在有无穷多种颜色,此时如果要涂的所有格子都已经有颜色了,说明被后面的覆盖了,涂啥对结果都没有影响,就不用管了,反之就能多涂一种颜色,设一共最多能涂t种颜色。

如何判断一个格子是否可以被涂色呢?用x和y数组表示,如果这行/列已经被涂色了就打个标记,不能被涂色只可能是横竖都有标记或者横有标记但是横的都满了

因为只有k个颜色,所以总方案数为k^t

顺带一提,怎么会有傻逼if又写错,就像怎么会有傻逼区域赛数据范围看错呢

#include<bits/stdc++.h>using namespace std;int x[200005];int y[200005];int a[200005][3];int main(){int _,n,m,k,p;cin >> _;while (_--){memset(x,0,sizeof(x));memset(y,0,sizeof(y));int sum = 0;cin >> n >> m >> k >> p;for (int i = 1; i <= p ; i++){cin >> a[i][1] >> a[i][2];}for (int i = p; i >= 1; i--){if (x[a[i][1]] == 0 && y[a[i][2]] == 0){x[a[i][1]] = 1;y[a[i][2]] = 1;sum++;x[0]++;y[0]++;}else{if (x[a[i][1]] != 0 && y[a[i][2]] != 0){continue;}else{if (x[a[i][1]] == 0){if (y[0] != m){x[a[i][1]] = 1;sum++;x[0]++;}}else{if (x[0] != n){y[a[i][2]] = 1;sum++;y[0]++;}}}}}long long ans=1;for (int i = 1; i <= sum; i++){ans = ans * k % 998244353;}cout<<ans<<"
"; }}

E:有一个n*n的网格,从1,1出发,给一个只有d和r的序列,遇到d可以向下走1步,遇到r向右走1步,现在告诉你可以用dd替代d,rr替代r(即走1步变成走若干步),问在总路径不走出边界的情况下有哪些格子能被走到

题解:能走到的肯定是一块整体,因此找出不能走到的就行

不能走到的分为上面和下面两块,如果第一步向右,则右上角的剩余块就是将第一步向右延伸到可以延伸的最长位置的剩余块面积,左下角分为两块,一块是开头连续的R,为R*n-R,后面的部分类比右上角,直接往下推就行

注意将只有D or R的情况特殊处理

不写longlong见祖宗

#include<bits/stdc++.h>
using namespace std;
char s[200000008];
int main()
{
	long long _, n;
	cin >> _;
	long long ans;
	while (_--)
	{
		long long sumx = 0, sumy = 0, x, y;
		cin >> n >> s;
		
		ans=n*n;
		//cout<<ans;
		x = n - 1;
		y = n - 1;
		int num1=0,num2=0,flag1=0,flag2=0;
		for (int i = 0; i < strlen(s); i++)
		{
			if (s[i] == 'D')
			{
				y--;
				flag1=1;
				if(flag2==0)
				num1++;
			}
			else
			{
				flag2=1;
				x--;
				if(flag1==0)
				num2++;
			}
		}
		if(flag1==0||flag2==0)
		{
			cout<<n<<"\n";
			continue;
		}
		if (s[0] == 'D')
			sumx += (num1*x);
		else
			sumy += (y*num2);
		y = n - y - 1;
		x = n - x - 1;
		int x1 = 0, y1 = 0;
		for (int i = 0; i < strlen(s); i++)
		{
			if (s[i] == 'D')
			{
				y--;
				//sumy+=y;
				sumx += x;

			}
			else
			{
				x--;
				//sumx+=x;
				sumy += y;
			}
		}

		
		cout << ans - sumx - sumy << "\n";
//		10000
//100000000
//DDDDDRRDDRDDRD
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值