芝士一道通过率低于大多数紫题的毒瘤绿题
简简单单一个最大子段和,考试的时候倒也没有想到用什么前缀和来优化,一边一边更新答案就行,这里解释一下转移方程吧
定义:,到第个位置,之前选了段,当前这个点选/不选的最大子段和
至于为什么能够省略呢?因为这种dp方式实际上是最大段和的特殊情况,所以我们选了段,而当前这个却要选的情况实际上是没有意义的。
然而一测交上去是只有的,因为这个题数据范围是会爆的,但是我当时小算了下认为只会爆,所以就没有用,后面加了就行了
点击查看代码
| #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];int score[maxn];int ans=-2005120700; |
| signed main() |
| { |
| |
| |
| 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]); |
| dp[i][1][1]=max1(dp[i-1][1][1],dp[i-1][0][0])+a[i]; |
| |
| 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; |
| } |
给出一张有初始颜色的图,每次可以改变左上角的点的颜色,那么所有和他处于同一个颜色相同连通块内的点就可以随之改变,求最少多少次能够把整张图变成同一个颜色。
实际上原题并没有提到“连通块”这个词语,但是我仍然一眼看出来这道题的正解一定是搜索,没有为什么,芝士直觉,但是就是按照暴力改变原的颜色来进行搜索,但是很容易就死循环了,因为朴素搜索里面很容易就在两个状态之间反复横跳然后就死循环了,然后名正言顺地保龄了。
我们考虑有没有一种方式能够强硬的避免这种死循环,首先可以证明的是我们最多在的代价内就把所有的点联通了,也就是说并不会存在无解的情况,在这种指数级增长的状态数下,我们就能够掏出我们专门求“步数问题”的了,这样既减少了复杂度,又避免了死循环一直跳下去,然后对于每一次的操作,我们都会对当前的连通块引入新的点,增加其大小,所以并不需要更改原图,只需要记录当前点是不是在连通块内就行了
精华就在于 当前步数+预估步数>当前限制的层数的时候,我们直接掉。那么问题就在于我们该如何设计这个估值函数,要知道我们一般给的估值一般都是尽量少,以免错过可能的答案。在这道题中,除了连通块里面的颜色,外面每有一种颜色,我们就要至少多操作一次才能得到答案,所以我们的估值函数就是除联通块外其余的颜色种数
我们定义一个数组来记录当前点是否属于连通块,或者是否是一个可以被连通块影响到的点(即连通块的边缘),分别用来表示
另外,如果我们当前枚举要去填充的颜色并不能对当前图的连通性带来改变,就可以掉去考虑填充下一种颜色了,芝士一个极其重要的剪枝,会让代码直接快上两百毫秒左右
不想说屁话了,直接上代码吧
点击查看代码
| #include<cstdio> |
| #include<iostream> |
| #include<algorithm> |
| #include<cstring> |
| using namespace std; |
| const int maxn=11; |
| int c1[]={-1,0,0,1},c2[]={0,-1,1,0}; |
| int con[maxn][maxn],map[maxn][maxn],coltag[maxn]; |
| int n,deep; |
| |
| bool valid(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=n&&con[x][y]!=1;} |
| void paint(int x,int y,int col) |
| { |
| con[x][y]=1; |
| for(register int i=0;i<=3;++i) |
| { |
| int x1=x+c1[i],y1=y+c2[i]; |
| if(!valid(x1,y1))continue; |
| con[x1][y1]=2; |
| if(map[x1][y1]==col)paint(x1,y1,col); |
| } |
| } |
| int fill(int col) |
| { |
| int ans=0; |
| for(register int i=1;i<=n;++i) |
| for(register int j=1;j<=n;++j) |
| if(map[i][j]==col&&con[i][j]==2)ans++,paint(i,j,col); |
| return ans; |
| } |
| int evaluate() |
| { |
| int ans=0; |
| memset(coltag,0,sizeof coltag); |
| for(register int i=1;i<=n;++i) |
| for(register int j=1;j<=n;++j) |
| { |
| if(coltag[map[i][j]]||con[i][j]==1)continue; |
| coltag[map[i][j]]=1; |
| ans++; |
| } |
| return ans; |
| } |
| int dfs(int step) |
| { |
| int tmp=evaluate(); |
| if(step+tmp>deep)return 0; |
| if(tmp==0)return 1; |
| int mem[maxn][maxn]; |
| memcpy(mem,con,sizeof mem); |
| for(register int i=0;i<=5;++i) |
| { |
| if(!fill(i))continue; |
| if(dfs(step+1))return 1; |
| memcpy(con,mem,sizeof con); |
| } |
| return 0; |
| } |
| void reset(){memset(coltag,0,sizeof coltag);memset(con,0,sizeof con);} |
| int main() |
| { |
| while(1) |
| { |
| scanf("%d",&n);if(!n)break; |
| for(int i=1;i<=n;i++) |
| for(int j=1;j<=n;j++)scanf("%d",&map[i][j]); |
| paint(1,1,map[1][1]); |
| for(deep=0;deep>=0;deep++)if(dfs(0))break; |
| printf("%d\n",deep); |
| reset(); |
| } |
| return 0; |
| } |
很简洁的题意,给出一个序列,我们进行若干次操作,能够把任意两个数变成&,求可以得到序列所有平方和的最大值。
一言乱搞题,我们尽量把最大的数分配给一个数,一定会让这个序列的平方和变大,所以我们只用统计所数二进制下的位数,然后按贪心策略分配即可
点击查看代码
| #include<iostream> |
| #include<cstdio> |
| #include<cstring> |
| #include<algorithm> |
| #define int long long |
| using namespace std; |
| const int maxn=1e5; |
| int n,a[maxn]; |
| int s[21]; |
| void Sort(int x) |
| { |
| int cnt=0; |
| while(x) |
| { |
| s[cnt++]+=(x&1); |
| x>>=1; |
| } |
| } |
| signed main() |
| { |
| scanf("%lld",&n); |
| for(register int i=1;i<=n;++i) |
| { |
| scanf("%lld",&a[i]); |
| Sort(a[i]); |
| } |
| long long ans=0; |
| for(register int i=20;i>=0;--i) |
| { |
| while(s[i]) |
| { |
| int tmp=0; |
| for(register int j=i;j>=0;j--) |
| { |
| if(s[j]) |
| { |
| tmp+=1<<(j); |
| s[j]--; |
| } |
| } |
| ans+=tmp*tmp; |
| } |
| } |
| printf("%lld",ans); |
| return 0; |
| } |
明天来改
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效