首页 > 其他分享 >【题解】Educational Codeforces Round 151(CF1845)

【题解】Educational Codeforces Round 151(CF1845)

时间:2023-07-24 10:34:23浏览次数:38  
标签:151 Educational le int 题解 scanf freopen txt sum

VP战报:1h 过了 A,B,C,D 然后被 E 罚坐 1h
rank:210th
题解只有 A-E

A.Forbidden Integer

题目描述:

你需要构造一个正整数序列,满足:

  1. 对于 \(i\),\(a_i\le k\) 且 \(a_i\not=x\)。
  2. \(\sum a_i=n\)。

如无法构造,输出 NO,否则输出 YES 后,输出序列长度与序列中的每一个数。
多测 \(t \le 100\),\(1 \le n,k,x \le 100\)

题目分析:

我们显然可以全部使用 \(1\) 去构造,这个使用条件为 \(x \not= 1\)
或者不能用 \(1\) 就考虑使用 \(2,3\) 构造,尽可能使用 \(2\),最后如果有剩余的就将某一个 \(2\) 替换为 \(3\) 即可,使用条件自己列列就好了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		int n,k,x;scanf("%d%d%d",&n,&k,&x);
		if(x != 1){
			printf("YES\n");
			printf("%d\n",n);
			for(int i=1; i<=n; i++)	printf("1 ");
			printf("\n");
		}
		else{
			if(n == 1 || k == 1)	printf("NO\n");
			else if((n & 1) && k == 2)	printf("NO\n");
			else{
				int tmp = n / 2;
				printf("YES\n");
				printf("%d\n",tmp);
				for(int i=1; i<=tmp; i++){
					if((n & 1) && i == tmp)	printf("3 ");
					else	printf("2 ");
				}
				printf("\n");
			}
		}
	}
	return 0;
}

B.Come Together

题目描述:

给定无限大的网格图中 \(A\),\(B\),\(C\) 三点的横纵坐标,你需要求出,从 \(A\) 分别到 \(B\) 与 \(C\) 的最短路径最大有多少格点重合。
多测 \(t \le 10^4\),\(1 \le x,y \le 10^8\)

题目分析:

距离其实就是曼哈顿距离,所以考虑两维分别拆开。
对于其中一维如果 \(B,C\) 位于 \(A\) 的异侧显然除了 \(A\) 这个点不存在重合的点,否则如果在同侧则显然重合的个数就是距离 \(A\) 较近的点与 \(A\) 的距离。
两维贡献分别加和,然后特判一下 \(A\) 这个点的贡献即可

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%lld",&T);
	while(T--){
		int x1,x2,x3,y1,y2,y3;
		scanf("%lld%lld%lld%lld%lld%lld",&x1,&y1,&x2,&y2,&x3,&y3);
		int ans = 0;
		if((x2 >= x1 && x3 >= x1) || ((x2 <= x1 && x3 <= x1)))
			ans += min(abs(x2 - x1),abs(x3 - x1));
		if((y2 >= y1 && y3 >= y1) || ((y2 <= y1 && y3 <= y1)))
			ans += min(abs(y2 - y1),abs(y3 - y1));
		printf("%lld\n",ans + 1);
	}
	return 0;
}

C.Strong Password

题目描述:

给定一个字符串 \(s\),以及两个长度为 \(m\) 的字符串 \(l,r\)。你需要判断是否没有长度为 m 的字符串 \(t\) 满足以下要求:

  1. 对于 \(1\le i\le n\),\(l_i\le t_i\le r_i\)。
  2. \(t\) 不是 \(s\) 的一个子序列。

多测 \(t \le 10^4,1 \le |s| \le 3·10^5,1 \le m \le 10\),且给定串为数字串。

题目分析:

其实本质就是让我们判断是否所有的满足 \(1\) 条件的字符串都是 \(s\) 的子序列,这个形式显然好做多了,也就是在最坏情况下依旧是。
对于子序列一个常见的想法就是贪心匹配,也就是每次找到最靠前的一个出现的位置匹配,对于每一位我们可以贪心的这样匹配然后找到匹配出来的最靠后的位置作为我们这一位最劣的位置,然后从这个最劣的位置开始下一位的匹配。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
bool vis[N];
char s[N],l[N],r[N];
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);int m;scanf("%d",&m);
		scanf("%s%s",l+1,r+1);
		int n = strlen(s+1);
		int pos = 1,sz = 0;
		for(int i=1; i<=n; i++){
			if(l[pos] <= s[i] && s[i] <= r[pos] && !vis[s[i]-'0']){
				vis[s[i]-'0'] = true,sz++;
			}	
			if(sz == r[pos] - l[pos] + 1){
				++pos;sz = 0;
				if(pos == m + 1)	break;
				for(int j=0; j<=10; j++)	vis[j] = false;
			}
		}
		if(pos == m + 1)	printf("NO\n");
		else	printf("YES\n");
		for(int j=0; j<=10; j++)	vis[j] = false;
	}
	return 0;
}

D.Rating System

题目描述:

给定一个长度为 \(n\) 数列 \(a\),保证每项都不为 \(0\)。初始时 \(x=0\),然后对于 \(1\le i\le n\),按顺序进行如下操作:

  • 如果 \(x\ge k\),则 \(x\rightarrow \max(k, x+a_i)\),否则 \(x\rightarrow x+a_i\)。

你需要求出 \(k\),使得 \(x\) 的值尽量大。
多测 \(t \le 10^4,\sum_n \le 3·10^5,-10^9 \le a_i \le 10^9,a_i \not= 0\)

题目描述:

我们考虑随意指定一个 \(k\) 然后把 \(x\) 变化的折线图画出来,观察是否具有什么性质:

其实就是可以将整个过程分为三段,其中第一段和最后一段的贡献不受任何影响,第二段的贡献被强制变成了 \(0\)。
为了使得最后的值最大,我们显然要选择一个最小的子段和让它的贡献变成 \(0\),至于选择的 \(k\) 显然就是一个前缀和。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 6;
const int INF = 1e18+5;
int a[N];
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%lld",&T);
	while(T--){
		int n;scanf("%lld",&n);
		for(int i=1; i<=n; i++)	scanf("%lld",&a[i]);
		int nw = 0,l = 0;
		int ans1 = INF,ans2 = 0;
		for(int i=1; i<=n; i++){
			nw += a[i];
			if(nw > 0) l = 0,nw = 0;
			else{
				if(!l) l = i;
				if(nw < ans1) ans1 = nw,ans2 = l-1;
			}
		}
		int sum = 0;
		for(int i=1; i<=ans2; i++)	sum += a[i];
		printf("%lld\n",sum);
	}
	return 0;
}

E.Boxes and Balls

题目描述:

给定一个长度为 \(n\),由 \(0,1\) 构成的数组 \(a\)。你可以对他进行以下操作:

  • 交换数列中一对相邻的 \(0\) 和 \(1\)。

问在恰好 \(k\) 次操作后,可以产生多少种本质不同的数组。
\(2 \le n \le 1500,1 \le k \le 1500,a_i \in \{0,1\}\)

题目分析:

考虑什么样的最终状态是合法的。
可以发现的一点就是我们如果操作 \(t\) 次可以到达某个状态,操作 \(t+2\) 次也一定可以,因为我们可以重复操作某一个位置,所以为了不重其实我们只关系到达这个状态的最小操作次数。
那么考虑如果给定了一个最终状态 \(b\) 怎么计算它的最小操作次数,只用在意 \(1\) 的位置变化,因为确定了 \(1\) 就全部确定了。
可以对于每个位置计算跨过这个位置的次数,也就是设 \(s_i = \sum_{j=1}^i a_j,s'_i = \sum_{j=1}^i b_j\),也就是前 \(i\) 个有多少个 \(1\),那么最小操作次数就是 \(\sum |s_i - s'_i|\)
这样我们发现就可以将问题转化为一个看上去就很可做的形式,求有多少个序列 \(s\) 满足 \(s'_0 = 0,s'_n = n,|s'_{i} - s'_{i-1}| \le 1,\sum |s_i-s'_i| \le k,\sum |s_i - s'_i| \equiv k \mod 2\)
其实发现如果想要完整地表示这个状态要记录的值只有 \(s'_i\) 和 \(\sum |s_i - s'_i|\),所以就考虑设 \(f_{i,j,p}\) 表示前 \(i\) 个数 \(s'_i = j\) 且 \(\sum_{j=1}^i |s_j - s'_j| = p\) 的方案数。转移也是简单的,就是枚举 \(s'_{i-1}\):

\[f[i-1][j][p-|s_i - j|] + f[i-1][j-1][p-|s_i - j|] \to f[i][j][p] \]

下面默认 \(n,k\) 同阶,则复杂度就是 \(O(n^3)\) 需要稍微优化一下。
\(|s_i - s'_i|\) 的本质就是跨过 \(i\) 的 \(1\) 的数量,那么考虑对于 \(x\) 个数想要跨过 \(i\) 需要的操作数是 \(O(x^2)\) 的,也就是说其实 \(|s_i - s'_i|\) 不会超过 \(O(\sqrt{k})\),那么只需要枚举这些值就好了。
复杂度被优化到了 \(O(n^2\sqrt{n})\)

代码:

(感觉直接看的话循环边界会很抽象,不行就自己写写然后自己优化)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1505;
const int MOD = 1e9+7;
int f[2][N][N],a[N],s[N];
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,k;scanf("%lld%lld",&n,&k);
	for(int i=1; i<=n; i++){
		scanf("%lld",&a[i]);
		s[i] = s[i-1] + a[i];
	}
	f[0][0][0] = 1;
	for(int i=1; i<=n; i++){
		int now = i & 1,lst = now ^ 1;
		memset(f[now],0,sizeof(f[now]));
		for(int j=max(0ll,s[i]-50); j<=min(s[n],s[i]+50); j++){
			for(int p=abs(s[i]-j); p<=k; p++){
				if(j != 0)	f[now][j][p] = f[lst][j-1][p-abs(s[i]-j)];
				f[now][j][p] = (f[now][j][p] + f[lst][j][p-abs(s[i]-j)])%MOD;
			}
		}
	}
	int ans = 0;
	while(k >= 0){
		ans = (ans + f[n&1][s[n]][k])%MOD;
		k -= 2;
	}
	printf("%lld\n",ans);
	return 0;
} 

标签:151,Educational,le,int,题解,scanf,freopen,txt,sum
From: https://www.cnblogs.com/linyihdfj/p/17576479.html

相关文章

  • AT_abc180_d 题解
    洛谷链接&Atcoder链接本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读。题目简述现有\(STR\)和\(EXP\)两个变量,初始化分别为\(X\)和\(0\),可对变量\(STR\)做以下两种操作:将\(STR\)乘\(A\),并将\(EXP\)自加\(1\)。将\(STR\)加上\(B\),并将\(E......
  • P1387 最大正方形 题解
    注意细节通过二维前缀和判定矩形内是否全为1,计算和等于长度的平方就判断为是复杂度\(\Theta(n^2\log{n})\)#include<bits/stdc++.h>#defineN(int)(105)usingnamespacestd;intmp[N][N];ints[N][N];intn,m;boolcheck(intlenth){ for(inti=1;i+lenth......
  • Codeforces Round 886 (Div. 4) 题解 A - H
    A.ToMyCritics题目大意给定三个数,你可以挑俩数加起来,问这仨数有没有可能加起来大于等于\(10\).解题思路我们找其中最大的两个数相加与\(10\)比较即可。ACCode#include<iostream>#include<algorithm>#include<cstring>#defineendl'\n'#defineiosios::sync......
  • Codeforces Round 886 (Div. 4) 全题题解
    我关注的人中正式参与比赛排名公示:#Who=Penalty*ABCDEFGH1(980)Chen_Jinhui7381\(\color{#00CC00}{\textbf{+}}\)00:05\(\color{#00CC00}{\textbf{+1}}\)00:17\(\color{#00CC00}{\textbf{+}}\)00:19\(\color{#00CC00}{\textbf{+}}\)01:08......
  • 题解 P9474 [yLOI2022] 长安幻世绘
    看到极差,不难想到双指针。显然,如果\([l,r]\)的位置都被覆盖,那么其中最多可以选\(\lceil\frac{r-l+1}{2}\rceil\)个数。我们先将所有数离散化,排序,双指针卡取值范围。set里面存pair类型变量,表示覆盖的区间。每次将值为\(r\)的数的位置加入,在set中二分到与它相邻的区......
  • 题解链接
    积跬步,至千里tag:二分洛谷P1314聪明的质检员洛谷P1024一元三次方程求解tag:分块CF785EAntonandPermutationtag:贪心UVA1335/洛谷P4409皇帝的烦恼题解tag:倍增+贪心P4155、P6902——一类区间覆盖问题tag:二进制洛谷P7617KOMPIĆI的一个小tricktag:排列组合+......
  • 题解:【ICPC WF 2021 H】 Prehistoric Programs
    题目链接#include<bits/stdc++.h>#defineldlongdouble#defineuiunsignedint#defineullunsignedlonglong#defineintlonglong#defineebemplace_back#definepbpop_back#defineinsinsert#definempmake_pair#definepiipair<int,int>#def......
  • cf 题解
    MihaiandSlavicwerelookingatagroupof$n$frogs,numberedfrom$1$to$n$,allinitiallylocatedatpoint$0$.Frog$i$hasahoplengthof$a_i$.Eachsecond,frog$i$hops$a_i$unitsforward.Beforeanyfrogsstarthopping,SlavicandMihaicanp......
  • P7074 [CSP-J2020] 方格取数 题解
    题目:题目描述设有n*m 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。输入格式第一行有两个整......
  • AtCoder Beginner Contest 311 A-E题解
    A-FirstABC题意给一个长度为N的仅由ABC三个字符组成的字符串S,问S中ABC三个字符第一次出现的位置的最大值。题解使用map<char,bool>判重,记录当前不同的字符串的个数cnt,当cnt等于3时,输出此时的下标+1作为答案。Code#include<bits/stdc++.h>usingnamespacestd;usingll......