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_{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");
}