Welfare State
题意
有两个修改:1、将所有小于 x x x的改为 x x x。2、单点修改为 x x x。
题解
比赛的做法:
维护最小最大值,最小小于
x
x
x就向下递归,最大小于
x
x
x直接区间修改。
但是如果一小一大的数据可以卡满复杂度。
赛后做法:
我们可以发现,对于一个点最后的大小等于最后一次修改过后和
2
2
2操作修改的比较。
我们记录每个操作过后最大的
2
2
2修改。
最后结果:初值/替换之后:修改与每次修改过后最大比较。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn = 3e5+200;
int n,m;
int bb[maxn],aa[maxn],cc[maxn];
struct node{
int index,pos,val;
};
vector<node>vec;
int main(){
cin>>n;
FOR(i,1,n)scanf("%d",&aa[i]);
cin>>m;
FOR(i,1,m){
int op,p,x;scanf("%d",&op);
if(op==1){
scanf("%d%d",&p,&x);
vec.push_back(node{i,p,x});
}
else{
scanf("%d",&x);
bb[i]=x;
}
}
RFOR(i,m,1)cc[i]=max(cc[i+1],bb[i]);
FOR(i,1,n)aa[i]=max(cc[1],aa[i]);
for(auto it:vec){
aa[it.pos]=max(it.val,cc[it.index]);
}
FOR(i,1,n)printf("%d ",aa[i]);
}
Matching vs Independent Set
题意
要求找到
n
n
n个边的匹配或者
n
n
n个点的独立集。图有
3
n
3n
3n个点
匹配是指任意两个没有公共点。独立集是指任意两个点没有边相连。
题解
如果我们直接暴力找
n
n
n条边,每次标记边的两个点,不重复选有相同点的,这样子一定能满足第一个。
如果找不到,说明标记的点不超过
2
n
2n
2n,剩下的点就可以构成第二个。
如果剩下点还有公共边的话,那么在第一步操作里一定还可以继续标记。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn = 5e5+200;
int x[maxn],y[maxn];bool vis[maxn];
int n,m;
int node[maxn],edges[maxn],tot;
int main(){
int T;cin>>T;
while(T--){
scanf("%d%d",&n,&m);n=3*n;
FOR(i,1,m)scanf("%d%d",&x[i],&y[i]);
FOR(i,1,n)vis[i]=false;
tot=0;
FOR(i,1,m)if(!vis[x[i]]&&!vis[y[i]]){
vis[x[i]]=vis[y[i]]=true;
edges[++tot]=i;
}
if(tot>=n/3){
puts("Matching");
FOR(i,1,n/3)printf("%d%c",edges[i],i==n/3?'\n':' ');
continue;
}
tot=0;
FOR(i,1,n)if(!vis[i]){
vis[i]=true;
node[++tot]=i;
}
if(tot>=n/3){
puts("IndSet");
FOR(i,1,n/3)printf("%d%c",node[i],i==n/3?'\n':' ');
continue;
}
}
}
Rectangle Painting 1
题意
有一个矩形格子图,里面一部分黑色,一部分白色,每次可以把一个区域变成白色,花费是 m a x ( h , w ) max(h,w) max(h,w),问将所有格子涂成白色的最小花费。
题解
显然动规,但是太菜了没想出来(后面感觉懒的想了。
维护一个矩形的状态,那么一定是由小矩形形成的,但总不能枚举四维吧,这样加上大矩形,复杂度是
1
e
8
1e8
1e8。所以我们考虑分成两个操作,第一次竖着切,第二次横着切,这样在以后的操作也能够实现分割小矩形的操作,依然全面。
用记忆化搜索非常方便。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn = 1e5+200;
int n;
int dp[55][55][55][55];
char s[55][55];
int dfs(int x1,int x2,int y1,int y2){
if(x1==x2&&y1==y2)return s[x1][y1]=='#'?1:0;
if(dp[x1][x2][y1][y2]!=-1)return dp[x1][x2][y1][y2];
int &ret=dp[x1][x2][y1][y2];
ret=max(y2-y1+1,x2-x1+1);
FOR(i,x1,x2-1){
ret=min(ret,dfs(x1,i,y1,y2)+dfs(i+1,x2,y1,y2));
}
FOR(i,y1,y2-1){
ret=min(ret,dfs(x1,x2,y1,i)+dfs(x1,x2,i+1,y2));
}
return ret;
}
int main(){
cin>>n;
memset(dp,-1,sizeof(dp));
FOR(i,1,n)scanf("%s",s[i]+1);
dfs(1,n,1,n);
cout<<dp[1][n][1][n]<<endl;
}