10.31 模拟赛题解
T1:P1725 琪露诺
简单
暴力做是
发现每次查找一个区间内的
还可以单调队列优化,时间复杂度线性。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
const int N=4e5+10,INF=2e9;
int n,L,R,a[N],f[N],mx[N<<2];
void pushup(int u){mx[u]=max(mx[u<<1],mx[u<<1|1]);}
void modify(int u,int l,int r,int x,int v){
if(l==r){mx[u]=v;return;}
int mid=(l+r)>>1;
if(x<=mid) modify(u<<1,l,mid,x,v);
else modify(u<<1|1,mid+1,r,x,v);
pushup(u);
}
int query(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return mx[u];
int mid=(l+r)>>1,ans=-INF;
if(ql<=mid) ans=max(ans,query(u<<1,l,mid,ql,qr));
if(qr>mid) ans=max(ans,query(u<<1|1,mid+1,r,ql,qr));
return ans;
}
int main(){
n=rd,L=rd,R=rd;n++;
FOR(i,1,n) a[i]=rd;
memset(mx,-0x3f,sizeof(f)),f[1]=0;
modify(1,1,2*n,1,0);
FOR(i,1,n+R){
if(i-L<=0) continue;
f[i]=max(f[i],query(1,1,2*n,max(i-R,1),i-L)+a[i]);
modify(1,1,2*n,i,f[i]);
}
int ans=-INF;
FOR(i,n,n+R) ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
显然,一张二分图若要有恰好
但这还不够,上面这俩不是充要条件,反例很容易举出。
发现入度为
对于入度为
边,其他都无用了,可以删去。
所以我们要维护所有入度为
可以用拓扑排序的思想来做,存储入度为
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
#define debug cout<<"ILOVECCF!"<<endl;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
const int N=4e6+10;
int T,n,m,d[N],del[N];
vector<int> e[N];
bool toposort(){
memset(del,0,sizeof(del));
queue<int> q;int cnt=0;
FOR(i,1,2*n) if(d[i]==1) q.push(i);
while(!q.empty()){
int t=q.front();q.pop();
if(del[t]) continue;del[t]=1,cnt++;
int v;
for(auto y:e[t]){
if(!del[y]){v=y;break;}
}
if(!v) return false;
del[v]=1,cnt++;
for(auto y:e[v]){
if(!del[y]&&--d[y]==1) q.push(y);
}
}
return cnt==2*n;
}
int main(){
T=rd;
while(T--){
FOR(i,1,2*n) e[i].clear();memset(d,0,sizeof(d));
n=rd,m=rd;
FOR(i,1,m){
int x=rd,y=rd;y+=n;
d[x]++,d[y]++;
e[x].push_back(y),e[y].push_back(x);
}
if(toposort()) puts("Renko");
else puts("Merry");
}
return 0;
}
给你一个矩阵,子矩阵加、求子矩阵和,二维树状数组模版题。
类比一维树状数组维护区间加、区间和的思路即可,计算每个位置的出现次数。
最后需要开
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
const int N=3000;
int n,m,q;ll tr1[N][N],tr2[N][N],tr3[N][N],tr4[N][N];
int lowbit(int x){return x&-x;}
void add(int x,int y,int v,ll tr[][N]){
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
tr[i][j]+=v;
}
ll query(int x,int y,ll tr[][N]){
ll res=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
res+=tr[i][j];
return res;
}
void modify(int x,int y,int v){
add(x,y,v,tr1),add(x,y,v*x,tr2),add(x,y,v*y,tr3),add(x,y,v*x*y,tr4);
}
ll getsum(int x,int y){
return (x+1)*(y+1)*query(x,y,tr1)-(y+1)*query(x,y,tr2)-(x+1)*query(x,y,tr3)+query(x,y,tr4);
}
int main(){
char ch;cin>>ch;n=rd,m=rd;
while(cin>>ch){
int a=rd,b=rd,c=rd,d=rd,v;
if(ch=='k'){
v=rd;
modify(a,b,v),modify(c+1,d+1,v),modify(c+1,b,-v),modify(a,d+1,-v);
}
else{
printf("%lld\n",getsum(c,d)-getsum(a-1,d)-getsum(c,b-1)+getsum(a-1,b-1));
}
}
return 0;
}
贪心+线段树
首先模拟一下题中所述过程,发现是先把序列中点选出来,然后它的左右两边划分为两个数列,分别设为
接下来我们每次操作,选出一个数列最后的一个数,然后再另一个数列中删去一个数。
考虑暴力去做,可以先枚举答案区间,然后我们选择在区间的数,删去不在区间的最末端的数。这样做是最优的。
时间复杂度
容易发现,对于区间
还要继续优化,我们发现每次枚举答案区间,都要暴力的去模拟一遍上述过程,这是不可接受的。但发现每次移动区间左右端点,只会令某个数是否选择发生改变。
假如要选
所以对于每个位置,维护
直接上线段树就好了,区间修改,全局最小值。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
const int N=4e5+10;
int n,a[N],pos[N],mn[N<<2],tag[N<<2];
void pushup(int u){mn[u]=min(mn[u<<1],mn[u<<1|1]);}
void pushdown(int u){
tag[u<<1]+=tag[u],tag[u<<1|1]+=tag[u];
mn[u<<1]+=tag[u],mn[u<<1|1]+=tag[u];
tag[u]=0;
}
void build(int u,int l,int r){
if(l==r){mn[u]=l;return;}
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r),pushup(u);
}
void modify(int u,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr){mn[u]+=v,tag[u]+=v;return;}
pushdown(u);int mid=(l+r)>>1;
if(ql<=mid) modify(u<<1,l,mid,ql,qr,v);
if(qr>mid) modify(u<<1|1,mid+1,r,ql,qr,v);
pushup(u);
}
int main(){
n=rd;FOR(i,1,2*n+1) a[i]=rd,pos[a[i]]=i;
int l=1,r=0,ans=0;build(1,1,n);
while(r<=2*n+1){
if(mn[1]<0){
l++;
if(pos[l-1]==n+1) continue;
if(pos[l-1]<n+1) modify(1,1,n,pos[l-1],n,1);
else modify(1,1,n,2*n+2-pos[l-1],n,1);
}
else{
ans=max(ans,r-l+1),r++;
if(pos[r]==n+1) continue;
if(pos[r]<n+1) modify(1,1,n,pos[r],n,-1);
else modify(1,1,n,2*n+2-pos[r],n,-1);
}
}
printf("%d\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具