Test 2022.10.09

今天是今天专场

T1 小朋友的数字

芝士一道通过率低于大多数紫题的毒瘤绿题

分析

简简单单一个最大子段和,考试的时候倒也没有想到用什么前缀和来优化,一边O(n)dp一边更新答案就行,这里解释一下转移方程吧
定义:dp[i][2][2],到第i个位置,之前选了j段,当前这个点选/不选的最大子段和

{dp[i][0][0]=dp[i1][0][0];dp[i][1][0]=max1(dp[i1][1][1],dp[i1][1][0]);dp[i1][0][1]dp[i][1][1]=max1(dp[i1][1][1],dp[i1][0][0])+a[i];

至于为什么能够省略呢?因为这种dp方式实际上是最大k段和的特殊情况,所以我们选了0段,而当前这个却要选的情况实际上是没有意义的。

注意

然而一测交上去是只有85pts的,因为这个题数据范围是会爆longlong的,但是我当时小算了下认为只会爆int,所以就没有用int128,后面加了int128就行了

Code

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int __int128
using namespace std;
inline int read()
{
int x=0,f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
return x*=f;
}
inline void wr(int n)
{
if(n==0) return;
if(n<0)putchar('-'),n=-n;
wr(n/10);
putchar(n%10+'0');
}
inline int max1(int x,int y){return x>y?x:y;}
int abs1(int x){return x>=0?x:-x;}
const int maxn=1e6+100;
int n,p,a[maxn],dp[maxn][2][2];/*前i个选了j段第i个选或者不选的最大值*/int score[maxn];int ans=-2005120700;
signed main()
{
// freopen("number.in","r",stdin);
// freopen("number.out","w",stdout);
n=read(),p=read();
if(p==1){printf("0");return 0;}
for(register int i=1;i<=n;++i)a[i]=read();
int maxnum=-2005120700;
dp[1][1][1]=a[1];;dp[1][1][0]=-2005120700;
score[1]=dp[1][1][1];maxnum=max1(maxnum,score[1]+dp[1][1][1]);ans=max1(ans,score[1]);
for(register int i=2;i<=n;++i)
{
dp[i][0][0]=dp[i-1][0][0];
dp[i][1][0]=max1(dp[i-1][1][1],dp[i-1][1][0]);//not pick
dp[i][1][1]=max1(dp[i-1][1][1],dp[i-1][0][0])+a[i];//picked
score[i]=maxnum;ans=max1(ans,score[i]);
maxnum=max1(maxnum,score[i]+max1(dp[i][1][1],dp[i][1][0]));
}
wr(ans%p);
return 0;
}

T2 Flood_it

题意

给出一张有初始颜色的图,每次可以改变左上角的点的颜色,那么所有和他处于同一个颜色相同连通块内的点就可以随之改变,求最少多少次能够把整张图变成同一个颜色。

分析

实际上原题并没有提到“连通块”这个词语,但是我仍然一眼看出来这道题的正解一定是搜索,没有为什么,芝士直觉,但是就是按照暴力改变原map的颜色来进行搜索,但是很容易就死循环了,因为朴素搜索里面很容易就在两个状态之间反复横跳然后就死循环了,然后名正言顺地保龄了。

正解

我们考虑有没有一种方式能够强硬的避免这种死循环,首先可以证明的是我们最多在nn的代价内就把所有的点联通了,也就是说并不会存在无解的情况,在这种指数级增长的状态数下,我们就能够掏出我们专门求“步数问题”的IDA了,这样既减少了复杂度,又避免了死循环一直跳下去,然后对于每一次的操作,我们都会对当前的连通块引入新的点,增加其大小,所以并不需要更改原图,只需要记录当前点是不是在连通块内就行了

IDA*

精华就在于 当前步数+预估步数>当前限制的层数的时候,我们直接return掉。那么问题就在于我们该如何设计这个估值函数,要知道我们一般给IDA的估值一般都是尽量少,以免错过可能的答案。在这道题中,除了连通块里面的颜色,外面每有一种颜色,我们就要至少多操作一次才能得到答案,所以我们的估值函数就是除联通块外其余的颜色种数

其他的一些处理

我们定义一个con[][]数组来记录当前点是否属于连通块,或者是否是一个可以被连通块影响到的点(即连通块的边缘),分别用1,2来表示
另外,如果我们当前枚举要去填充的颜色并不能对当前图的连通性带来改变,就可以continue掉去考虑填充下一种颜色了,芝士一个极其重要的剪枝,会让代码直接快上两百毫秒左右
不想说屁话了,直接上代码吧

Code

点击查看代码

T3 位位运算

题意

很简洁的题意,给出一个序列,我们进行若干次操作,能够把任意两个数x,y变成x|y,x&y,求可以得到序列所有平方和的最大值。

分析

一言乱搞题,我们尽量把最大的数分配给一个数,一定会让这个序列的平方和变大,所以我们只用统计所数二进制下的位数,然后按贪心策略分配即可

Code

点击查看代码

T4 开车旅行

明天来改

posted @   Hanggoash  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
动态线条
动态线条end
点击右上角即可分享
微信分享提示