2024.7.21模拟赛4

模拟赛

不挂分比挂分打的更少。。。

Qyun%%%

T1 Lights Out on Tree

无脑 \(O(nq)\),赛时用树状数组和 \(dfs\) 序优化了一下,没想到没有暴力分。

其实菊花和链的都可以打的,下次注意。

我们看数据范围,能操作的只有一个黑点个数,只要涉及白点一定会炸。

所以考虑每一个黑点的贡献(跟前两天单独考虑贡献的好像差不多?)。

观察得,如果它和它的父亲颜色不同就会有贡献。

但是如果对于每一个黑点遍历它的所有白儿子,会炸。

我们反过来考虑,先假设每个点的儿子都是白的,如果有一个黑点的父亲是黑点,那么总的贡献就会减一,否则要加上一。(它也有父亲)

code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,m;
int a[N],cnt,d[N],fa[N],son[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++)
	{
		int x; scanf("%d",&x);
		fa[i]=x; son[x]++;
	}
	while(m--)
	{
		int c,res=0; scanf("%d",&c);
		for(int i=1;i<=c;i++)
		{
			scanf("%d",&d[i]);
			a[d[i]]=1; res+=son[d[i]];
		}
		for(int i=1;i<=c;i++) if(a[fa[d[i]]]) res--; else res++;
		printf("%d\n",res);
		for(int i=1;i<=c;i++) a[d[i]]=0;
	}
	return 0;
}

T2 Encryption (hard) (medium) (easy)

已经不知道咕了多少天了。。。

注意卡空间!!!

赛时 long long 直接炸!

首先想到单调队列优化 dp,但是有一个取模,直接否掉。

考虑暴力 \(f_{i,j}\) 表示前 \(i\) 位分成 \(j\) 个块的最大价值,记录前缀和,得到状态转移方程:

\[f_{i,j}=\min_{k=1}^{i-1}(f_{k,j-1}+(s_i-s_k)\ mod\ p) \]

然后考虑优化,首先观察性质:

\[f_{i,j} \equiv s_i \pmod {p} \]

所以如果 \(f_{x,j}>f_{y,j}\),那么 \(f_{x,j}-(s_x\ mod\ p)>f_{y,j}-(s_y\ mod\ p)\)

因此我们只需要找到最小的 \(f_{k,j}\) 就是最优的。不用单调队列维护,直接开一个变量记一下就好了。

注意 \(5e5 \times 100\) 开 long long 会炸空间,提前算一下。

code
#include<bits/stdc++.h> 
using namespace std;
const int N = 5e5+5;
#define LL long long
int n,k,p,a[N],s[N];
int f[N][101],pos[101];
int main()
{
	memset(f,0x3f,sizeof(f));
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i]=(s[i-1]+a[i])%p;
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int h=1;h<=k;h++)
		{
			f[i][h]=f[pos[h-1]][h-1]+(s[i]-s[pos[h-1]]+p)%p;
		}
		for(int j=1;j<=k;j++) if(f[i][j]<f[pos[j]][j]) pos[j]=i;
	}
	printf("%d\n",f[n][k]);
	return 0;
}

T3 ± Increasing Sequence

先随便造一个单调递增串 \(S\),如果这个串就已经满足条件,直接输出。(注意判断这一步,万一真碰上了呢)

然后考虑对这个串进行修改,并且不能改变原有的递增关系。

因此我们考虑对前缀和后缀整体进行操作,这样让前缀减一个值,后缀加一个值,一定不会改变递增关系的。

所以我们遍历所有前缀,如果目前 \(sum\) 大于 \(0\),那么碰到一个前缀修改操作和大于 \(0\) 的就可以减去差值,直接输出。

其他情况同理,还有后缀的。

code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
#define LL long long
int n,a[N],s1[N],s2[N];
LL tot,ans[N];
int main()
{
//	freopen("1.in","r",stdin);
//	freopen("o1.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scnaf("%d",&a[i]),s1[i]=s1[i-1]+a[i];
	for(int i=n;i>=1;i--) s2[i]=s2[i+1]+a[i];
	for(int i=1;i<=n;i++) ans[i]=i,tot+=i*a[i];
	if(tot==0)
	{
		printf("Yes\n");
		for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
		return 0;
	}
	if(tot<0)
	{
		for(int i=1;i<=n;i++) if(s1[i]<0) 
		{
			printf("Yes\n");
			for(int j=1;j<=n;j++) j<=i?printf("%lld ",ans[j]+tot):printf("%lld ",ans[j]);
			return 0;
		}	
		for(int i=n;i>=1;i--) if(s2[i]>0)
		{
			printf("Yes\n");
			for(int j=1;j<=n;j++) j>=i?printf("%lld ",ans[j]-tot):printf("%lld ",ans[j]);
			return 0;
		}
	}
	else
	{
		for(int i=1;i<=n;i++) if(s1[i]>0) 
		{
			printf("Yes\n");
			for(int j=1;j<=n;j++) j<=i?printf("%lld ",ans[j]-tot):printf("%lld ",ans[j]);
			return 0;
		}
		for(int i=n;i>=1;i--) if(s2[i]<0)
		{
			printf("Yes\n");
			for(int j=1;j<=n;j++) j>=i?printf("%lld ",ans[j]+tot):printf("%lld ",ans[j]);
			return 0;
		}
	}
	printf("No\n");
}

T4 捉迷藏

posted @ 2024-07-28 07:17  ppllxx_9G  阅读(18)  评论(0编辑  收藏  举报