NOI模拟24
垫底加啥也不是,但是感觉啥都会呵呵呵
原题,不多说什么,做T1的时间有点多了,T2就只有暴力,没怎么化式子,T3就没有写...
T1 CF590E
这里就一个知识点,有关于有向无环图的最大独立集问题
既然是有向无环图,这个东西的最大独立集也就是最长反链等于最小可重链划分
于是这个不太好搞,于是把有向无环图用Floyd跑一下传递闭包,于是变成了偏序集,用dilworth定理就是最小链划分了
拆点,然后跑网络流就行了,我们想要构造最长反链的方案
我们知道最长反链也就是最大独立集等于最小点覆盖的补集,我们想要找到最小点覆盖,取补集就是最大独立集了
我们从拆出来的右侧的点中没有匹配的点开始搜,从右向左走非匹配边,从左向右走匹配边
这时候我们要左侧被搜到的点,右侧未被搜到的点,这些就是二分图的最小点覆盖,为什么
对于匹配边来说,如果选了左侧的点,也就说左侧的点被搜到了,那么经过这个边一定可以搜到右侧对应的点,于是右边就不选了,相反,如果左侧未搜到,那么右侧也搜不到,于是就选上了右边的点
对于非匹配边来说,如果右侧是非匹配点的话,那么走这条边就可以走到左边,于是选上了左边的点,右侧若是匹配点,那么左侧一定是非匹配点,如果右侧被搜到,那么左侧也可以被搜到,如果右侧没有被搜到,那么就选右边的点喽
于是残量网络上这样搞一搞我们就找到了最小点覆盖,但是这是拆完点之后的啊,咋弄回去,不会!
我们先取补集,然后在两侧都是补集的点就是原图的最长反链上的点
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=755;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
int n;char ch[M];vector<char> s[N];
int tail[N],id[N],sz[N];
bool com(int x,int y){return sz[x]<sz[y];}
struct AC{
struct POT{int son[2],fail;}tr[M];
int seg,dfn[M],dfm[M],cnt,id[M],sz[M],cid;
queue<int> q;
void build(){
fo(i,0,1)if(tr[0].son[i])q.push(tr[0].son[i]);
while(!q.empty()){
int x=q.front();q.pop();
id[++cid]=x;
fo(i,0,1){
if(tr[x].son[i])tr[tr[x].son[i]].fail=tr[tr[x].fail].son[i],q.push(tr[x].son[i]);
else tr[x].son[i]=tr[tr[x].fail].son[i];
}
}
fu(i,cid,1){
int x=id[i];
sz[x]++;
sz[tr[x].fail]+=sz[x];
}
sz[0]++;dfn[0]=1;dfm[0]=sz[0];
fo(i,1,cid){
int x=id[i];
dfn[x]=dfn[tr[x].fail]+1;
dfm[x]=dfn[x]+sz[x]-1;
dfn[tr[x].fail]+=sz[x];
}
fo(i,0,cid)dfn[i]=dfm[i]-sz[i]+1;
}
}ac;
struct BIT{
int tr[M];
inline void ins(int x){
for(int i=x;i<=ac.seg+1;i+=(i&-i))tr[i]++;
}
inline void clr(int x){
for(int i=x;i<=ac.seg+1&&tr[i];i+=(i&-i))tr[i]=0;
}
inline int qry(int x){
int ret=0;
for(int i=x;i;i-=(i&-i))ret+=tr[i];
return ret;
}
inline int qey(int l,int r){
return qry(r)-qry(l-1);
}
}bit;
int ie[N];
struct NET{
struct E{int to,nxt,val;}e[N*N*3];
int head[N*2],hea[N*2],rp=1,s,t;
void add_edg(int x,int y,int z){
e[++rp].to=y;e[rp].nxt=head[x];
e[rp].val=z;head[x]=rp;
}
int dis[N*2];
bool bfs(){
memcpy(head,hea,sizeof(int)*(n*2+5));
memset(dis,0x3f,sizeof(int)*(n*2+5));
queue<int> q;while(!q.empty())q.pop();
q.push(s);dis[s]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!e[i].val||dis[y]<=dis[x]+1)continue;
dis[y]=dis[x]+1;q.push(y);
if(y==t)return true;
}
}return false;
}
int dfs(int x,int in){
if(x==t)return in;
int rest=in,go;
for(int i=head[x];i;head[x]=i=e[i].nxt){
int y=e[i].to;
if(!e[i].val||dis[y]!=dis[x]+1)continue;
go=dfs(y,min(e[i].val,rest));
if(go)rest-=go,e[i].val-=go,e[i^1].val+=go;
else dis[y]=0;
if(!rest)break;
}return in-rest;
}
int dinic(){
memcpy(hea,head,sizeof(int)*(n*2+5));
int ret=0;
while(bfs())ret+=dfs(s,inf);
return ret;
}
bool vis[N*2];
void pdfs(int x){
if(vis[x]||x==t||x==s)return ;vis[x]=true;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(e[i].val)continue;
pdfs(y);
}
}
void print(){
memcpy(head,hea,sizeof(head));
fo(i,1,n)if(e[ie[i]].val)pdfs(i*2);
fo(i,1,n)if(!vis[i*2-1]&&vis[i*2])printf("%d ",i);
}
}net;
signed main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
n=read();
int sm=0;bool flag=false;
fo(i,1,n){
scanf("%s",ch+1);sz[i]=strlen(ch+1);
fo(j,1,sz[i])s[i].push_back(ch[j]);
int now=0;
for(char ss:s[i]){
if(!ac.tr[now].son[ss-'a'])ac.tr[now].son[ss-'a']=++ac.seg;
now=ac.tr[now].son[ss-'a'];
}tail[i]=now;
if(i==4&&ch[1]=='b'&&ch[2]=='b'&&sz[i]==2)flag=true;
}
ac.build();
fo(i,1,n){
int now=0;
for(char ss:s[i]){
now=ac.tr[now].son[ss-'a'];
bit.ins(ac.dfn[now]);
}
fo(j,1,n)if(sz[j]<sz[i]){
if(bit.qey(ac.dfn[tail[j]],ac.dfm[tail[j]])){
// assert()
// if(flag&&i==58)cout<<j<<" ";
net.add_edg(j*2-1,i*2,1);
net.add_edg(i*2,j*2-1,0);
}
}
// if(flag&&i==58)cout<<endl;
now=0;
for(char ss:s[i]){
now=ac.tr[now].son[ss-'a'];
bit.clr(ac.dfn[now]);
}
}
net.s=2*n+1;net.t=2*n+2;
fo(i,1,n){
net.add_edg(net.s,i*2-1,1);net.add_edg(i*2-1,net.s,0);
net.add_edg(i*2,net.t,1);
ie[i]=net.rp;
net.add_edg(net.t,i*2,0);
}
printf("%d\n",n-net.dinic());
net.print();
}
T2 AGC031D
对于一个变换我们将之变为先从\(p_i\)映射回\(i\),再从\(i\)映射到\(q_i\)
于是这里涉及到一个知识,对于一个矩阵\(A*B*C*D\)来说,它的逆矩阵是\(D^{-1}*C^{-1}*B^{-1}*A^{-1}\)
于是我们推着推着发现增量出现了循环节
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=1e5+5;
int n,m;
struct node{
int x[N];
node(){fo(i,1,n)x[i]=i;}
node operator * (node a)const{
node ret=*this;
fo(i,1,n)ret.x[i]=a.x[ret.x[i]];
return ret;
}
void print(){
fo(i,1,n)printf("%d ",x[i]);
printf("\n");
}
}pa,pb,qa,qb,ma,mb,xa,xb;
node nksm(node x,int y){
node ret;
while(y){
if(y&1)ret=ret*x;
x=x*x;y>>=1;
}return ret;
}
signed main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
n=read();m=read();
fo(i,1,n)pa.x[i]=read(),pb.x[pa.x[i]]=i;
fo(i,1,n)qa.x[i]=read(),qb.x[qa.x[i]]=i;
if(m==1)return pa.print(),0;m-=2;
fo(i,1,n)ma.x[i]=i;mb=qa;
xa=qb*pa*qa*pb;xb=qa*pa*qb*pb;
ma=ma*nksm(xa,m/6);
mb=nksm(xb,m/6)*mb;
if(m%6>=1)mb=pb*mb;
if(m%6>=2)ma=ma*qb;
if(m%6>=3)ma=ma*pa,mb=qb*mb;
if(m%6>=4)mb=pa*mb;
if(m%6>=5)ma=ma*qa;
if(m%6>=6)ma=ma*pb,mb=qa*mb;
(ma*mb).print();
}
T3 AGC026E
结论题,不在多说,用string转移即可!!
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=3005;
int n;
int pa[N],pb[N],ca,cb,id[N*2];
string f[N],s;
signed main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n=read();cin>>s;s=' '+s;
fo(i,1,2*n){
if(s[i]=='a')pa[id[i]=++ca]=i;
else pb[id[i]=++cb]=i;
}
pa[n+1]=pb[n+1]=2*n+1;id[2*n+1]=n+1;
fu(i,n,1){
f[i]=f[i+1];
if(pa[i]<pb[i]){
fo(j,i+1,n+1)if(pa[j]>pb[i]&&pb[j]>pb[i]){
// cerr<<j<<" "<<"ab"+f[j]<<endl;
f[i]=max(f[i],"ab"+f[j]);
break;
}
}
else {
int now=1;string st="b";
fo(j,pb[i]+1,2*n){
if(id[j]<i)continue;
if(s[j]=='a'){
now--;st+='a';
if(!now){
now=j+1;
break;
}
}
else {
now++;st+='b';
}
}
// cerr<<now<<endl;
f[i]=max(f[i],st+f[id[now]]);
}
// cout<<f[i]<<endl;
}
cout<<f[1];
}