日常刷题2025-3-5
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-139.日常训练2025-1-1410.日常训练2025-1-1511.日常训练2025-1-1612.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-2217.日常刷题2025-1-2318.日常训练2025-1-2419.日常刷题2025-1-2520.日常刷题21.日常刷题2025-2-622.日常刷题2025-2-923.日常刷题2025-2-1424.日常刷题2025-2-1525.日常刷题2025-2-1726.日常刷题2025-2-2027.日常刷题2025-2-2128.日常刷题2025-2-2229.日常刷题2025-2-2430.日常刷题2025-2-2631.日常刷题2025-2-2732.日常刷题2025-2-2833.日常刷题2025-3-134.日常刷题2025-3-235.日常刷题2025-3-3
36.日常刷题2025-3-5
37.日常刷题2025-3-638.日常刷题2025-3-739.日常刷题2025-3-840.日常刷题2025-3-941.日常刷题2025-3-1042.日常刷题2023-3-1143.日常刷题2025-3-1344.非常棒的二分和DP日常刷题2025-3-5
P8472 [Aya Round 1 G] 咕噜论坛(post)
绿色
正解:双指针
本题不是一维数组,而是二维矩阵,对于一维数组枚举区间,我们需要枚举起点和终点,时间复杂度是
此题非常具有参考价值!!!
代码
#include<bits/stdc++.h> #define up(l,r,i) for(int i=l,END##i=r;i<=END##i;++i) #define dn(r,l,i) for(int i=r,END##i=l;i>=END##i;--i) using namespace std; typedef long long i64; const int INF =2147483647; const int MAXN=500+3; int A[MAXN][MAXN],B[MAXN][MAXN],C[MAXN][MAXN]; int qry(int T[][MAXN],int l1,int l2,int r){ return T[l2][r]-T[l1-1][r]; } char S[MAXN][MAXN]; int n,m,k; int qread(){ int w=1,c,ret; while((c=getchar())> '9'||c< '0') w=(c=='-'?-1:1); ret=c-'0'; while((c=getchar())>='0'&&c<='9') ret=ret*10+c-'0'; return ret*w; } int ans=-1,a1,a2,a3,a4,a5; int main(){ n=qread(),m=qread(),k=qread(); up(1,n,i) scanf("%s",S[i]+1); up(1,n,i) up(1,m,j){ A[i][j]=(S[i][j]=='P')+A[i-1][j]; B[i][j]=(S[i][j]=='B')+B[i-1][j]; C[i][j]=(S[i][j]=='G')+C[i-1][j]; } up(1,n,i) up(i,n,j){ int sp=0,sb=0,sg=0,lp=1,lb=1,lg=1,x=j-i+1; up(1,m,r){ int wp=qry(A,i,j,r); sp+=wp; int wb=qry(B,i,j,r); sb+=wb; int wg=qry(C,i,j,r); sg+=wg; if(wp ) lb=r+1,lg=r+1,sb=sg=0; if(wb||wg) lp=r+1,sp=0; // while(lp<=r&&x*(r-lp+1)-sp>k) sp-=qry(A,i,j,lp),++lp; 此行代码是不必要的 while(lb<=r&&x*(r-lb+1)-sb>k) sb-=qry(B,i,j,lb),++lb; while(lg<=r&&x*(r-lg+1)-sg>k) sg-=qry(C,i,j,lg),++lg; if(x*(r-lp+1)>ans) ans=x*(r-lp+1),a1=i,a2=lp,a3=j,a4=r,a5='P'; if(x*(r-lb+1)>ans) ans=x*(r-lb+1),a1=i,a2=lb,a3=j,a4=r,a5='B'; if(x*(r-lg+1)>ans) ans=x*(r-lg+1),a1=i,a2=lg,a3=j,a4=r,a5='G'; } } up(a1,a3,i) up(a2,a4,j) S[i][j]=a5; printf("%d\n",ans); up(1,n,i) printf("%s\n",S[i]+1); return 0; }
P8590 『JROI-8』这是新历的朝阳,也是旧历的残阳
绿色
正解:双指针+公式化简
三个重要的点
-
题目中给的数组是单调不减的数组
-
由于中间可以插入空区间,所以为了让答案最大正数无脑放到最后一个区间,对于负数满足
的 分到第一段,其余的负数分到最后一段。所以一定会存在一个分界点 ,分界点左边满足公式 ,右边满足 。 -
当m增大时,只可能会有更多的负数被分到右边,所以 m 增大,t 不会右移,这是可以双指针的基础。
根据第二个点,我们需要对公式进行化简。
具体过程参考题解https://www.luogu.com.cn/article/1h6k19g9
评述
没有好好看题,完全不知道数组单调不减这个信息,搞得连划分方法都没想到。还有就是我对公式一点都不敏感,看到公式根本就不想化简。
代码
#include<bits/stdc++.h> #define int long long #define mod 998244353 using namespace std; //long long也是要开的 int n,k; int ans; int a[1000005]; int s1,s2; signed main(){ ios::sync_with_stdio(0); cin>>n>>k; int t=n; for(int i=1;n>=i;i++)cin>>a[i]; for(int i=1;n>=i;i++){ ans=(ans+(a[i]*a[i])%mod)%mod; s1=(s1+a[i])%mod;//前缀和 } ans=(ans*k)%mod;//直接在最开始就将序列平方和乘上k,在循环时不用单独计算。 for(int i=1;k>=i;i++){ while((a[t]+1)*(a[t]+1)<(a[t]+i)*(a[t]+i)&&t){ s1=(s1-a[t]+mod)%mod;s2=(s2+a[t])%mod; t--;//对于每个m,更新t和s1,s2。 } ans=(ans+(((i*i)%mod)*(n-t))%mod+t+(2*s1)%mod+(2*i*s2)%mod+mod)%mod; //注意取模。 } cout<<ans<<endl; return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18751950
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步