# 191003NOI模拟题解

T1：

Code：

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e6+5,INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f;
inline void add(int x,int y,int z,int w){
}
ll d[N];
int pt[N];
int s,t;
inline bool spfa(){
queue<int>q;q.push(s);
for(int i=1;i<=t;i++) d[i]=inf;
d[s]=0;
while(!q.empty()){
int x=q.front();q.pop();pt[x]=0;
int y=vis[i];
if(c[i]>0 && d[y]>d[x]+e[i]){
d[y]=d[x]+e[i];
if(!pt[y]){q.push(y);pt[y]=1;}
}
}
}
return d[t]!=inf;
}
int mxflow=0;ll mncost=0;
int cur[N];
ll ans=INF;
inline int dfs(int v,int flow){
if(v==t){mxflow+=flow;return flow;}
int res=0;pt[v]=1;
for(int i=cur[v];i;i=nxt[i]){
int y=vis[i];
if(!pt[y] && d[y]==d[v]+e[i] && c[i]){
cur[v]=i;
int k=dfs(y,min(flow-res,c[i]));
c[i]-=k;c[i^1]+=k;res+=k;mncost+=1ll*k*e[i];
if(res==flow) break;
}
}
pt[v]=0;
return res;
}
ll sum=0;
signed main(){
for(int x,y,i=1;i<=m;i++){
sum+=z;if(z<=0) continue;
}
s=0,t=n+n+1;
mcmf();cout<<sum+ans;
return 0;
}


T2：给你一个最大50x50的矩阵，每个点有一个要求的颜色，或者这个点禁止粉刷，现在可以用任意颜色粉刷任意一行或列，求每个点粉刷成要求颜色的最少次数并输出方案

Code：

#include<bits/stdc++.h>
#define pb push_back
#define db double
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
namespace topsort{
const int N=205,M=40005;
int in[N],pt[N];
vector<int>rk;
inline bool topsort(int n){
queue<int>q;rk.clear();
for(int i=1;i<=n;i++) if(pt[i] && !in[i]) q.push(i);
while(!q.empty()){
int x=q.front();q.pop();rk.pb(x);
int y=vis[i];--in[y];
if(!in[y]) q.push(y);
}
}
for(int i=1;i<=n;i++) if(in[i]) return 0;
return 1;
}
}
using namespace topsort;
const int NN=55;
int col[NN][NN],tmp[NN][NN];
int n,m,c;
struct info{
int op,num,col;
info(){}
info(int _op,int _num,int _col):op(_op),num(_num),col(_col){}
};
vector<info>ans,now;
int R[NN],C[NN],flag=0;
inline bool check(int x){
for(int i=1;i<=m;i++) C[i]=col[x][i];
for(int i=1;i<=n;i++) R[i]=-1;
R[x]=0;clear();
for(int i=1;i<=n;i++){
if(x==i) continue;
for(int j=1;j<=m;j++) if(C[j]!=col[i][j]){
if(C[j]!=0 && col[i][j]==0) return false;
if(R[i]==-1) R[i]=col[i][j];
else if(R[i]!=col[i][j]) return false;
}
if(R[i]==-1) R[i]=0;
if(R[i]==0) continue;
for(int j=1;j<=m;j++){
if(C[j]==0) continue;
}
}
for(int i=1;i<=n;i++) pt[i]=R[i]!=0;
for(int i=1;i<=m;i++) pt[n+i]=C[i]!=0;
if(!topsort::topsort(n+m)) return false;
now.clear();
for(int i=0;i<rk.size();i++){
if(rk[i]<=n) now.pb(info(0,rk[i],R[rk[i]]));
else now.pb(info(1,rk[i]-n,C[rk[i]-n]));
}
return true;
}
inline void file(){freopen("airline.in","r",stdin);freopen("airline.out","w",stdout);}
int main(){
for(int i=1;i<=n;i++)
for(int i=1;i<=n;i++) if(check(i) && (!flag || ans.size()>now.size())) ans=now,flag=1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) tmp[j][i]=col[i][j];
for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) col[i][j]=tmp[i][j];
swap(n,m);
for(int i=1;i<=n;i++) if(check(i) && (!flag || ans.size()>now.size())) ans=now,flag=2;
if(flag){
if(flag==2) for(int i=0;i<ans.size();i++) ans[i].op^=1;
cout<<ans.size()<<"\n";
for(int i=0;i<ans.size();i++) cout<<(ans[i].op?"C":"R")<<" "<<ans[i].num<<" "<<ans[i].col<<"\n";
}
else puts("-1");
return 0;
}


T3：有一棵树，1为根，初始每个叶子结点被占领，每个被占领的点每秒会产出一个士兵，士兵会一直往根节点走，走到根节点后自动消失，走到一个没有被占领的节点时会对其造成1点损伤，当一个没被占领的节点受到等同于其防御值的伤害后会被占领，求所有节点最晚多久被全部占领，规模100000

1.排序
2.二分查询前缀和
3.合并

Code：

#include<bits/stdc++.h>
#define db double
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=5e5+5;
int n,a[N];
const int rt=1;
int root[N],que[N];
struct Splay{
int fa[N],c[N][2];
ll key[N],sum[N];
int size[N],sz;
inline void pushup(int d){
sum[d]=sum[c[d][0]]+sum[c[d][1]]+key[d];
size[d]=size[c[d][0]]+size[c[d][1]]+1;
}
inline void rotate(int p,int x){
int mark=p==c[x][1],y=c[p][mark^1];
int z=fa[x];
if(x==c[z][0])c[z][0]=p;
if(x==c[z][1])c[z][1]=p;
if(y!=0)fa[y]=x;
fa[p]=z;c[p][mark^1]=x;
fa[x]=p;c[x][mark]=y;
pushup(x);
}
inline void splay(int p,int &rt){
while(fa[p]){
int x=fa[p],y=fa[x];
if(y==0)rotate(p,x);
else if(x==c[y][0]^p==c[x][0]) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}
rt=p;
pushup(p);
}
int newnode(){++sz;c[sz][0]=c[sz][1]=0;fa[sz]=0;return sz;}
inline void insert(ll k,int y,int pos){
int now=root[y],f=now,mark=0;
while(now){
f=now;
if(key[now]<=k)now=c[now][mark=1];
else now=c[now][mark=0];
}
now=pos;
fa[now]=f;if(f!=0)c[f][mark]=now;
c[now][0]=c[now][1]=0;key[now]=k;
splay(now,root[y]);
}
inline ll upperbound(ll k,int y){
int now=root[y],f=now;
while(now){
if(key[now]<=k){
if(f==root[y] && key[f]<=key[now]) f=now;
now=c[now][1];
}
else f=now,now=c[now][0];
}
splay(f,root[y]);
return k*size[c[f][0]]-sum[c[f][0]];
}
inline void merge(int x,int y){
if(size[root[x]]>size[root[y]]) swap(root[x],root[y]);
if(c[x][0])que[tail++]=c[x][0];
if(c[x][1])que[tail++]=c[x][1];
insert(key[x],y,x);
}
}
}tt;
int fa[N];
ll dis[N],mx[N],t[N];
void dfs(int u){
int v=vis[i];
if(v==fa[u]) continue;
fa[v]=u;dis[v]=dis[u]+c[i];
dfs(v);
mx[u]=max(mx[v]+c[i],mx[u]);
}
}
void dfs2(int u){
tt.insert(1ll<<60,u,tt.newnode());
int v=vis[i];
if(v==fa[u])continue;
dfs2(v);tt.merge(v,u);
}
ll l=0,r=mx[u]+a[u];
while(l<r){
ll mid=l+r>>1;
if(tt.upperbound(mid+dis[u],u)>=a[u]) r=mid;
else l=mid+1;
}
t[u]=r;
tt.insert(r+dis[u],u,tt.newnode());
}
inline void file(){freopen("conquer.in","r",stdin);freopen("conquer.out","w",stdout);}
int main(){
for(int x,y,z,i=1;i<n;i++){
}
dfs(rt);dfs2(rt);
ll ans=0;
for(int i=1;i<=n;i++) ans=max(ans,t[i]);
cout<<ans;
return 0;
}


09-08 89

07-31 3138

12-03 7915

02-15 3万+

03-01 4297

09-28 6076

02-22 5154

04-14 2525

02-05 3121

06-13 46

#### 俄罗斯方块

©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。