今日小测,搜了一下发现是GDSOI2018模拟4.19
sequence
我的方法和题解不太一样:
对于每个差= 的有序点对 连边 ,答案就是二分图最大匹配数(等价于最小点覆盖数)
连边是 的,发现可以栈贪心匹配不用实际跑二分图于是复杂度就 了。
正确性玄学。
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e6+10,M=1e7+10,inf=2e9;
typedef long long ll;
typedef double db;
int n,a[N],ans;
char buf[(1<<15)];int p1=0,p2=0;
inline char gc()
{
if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
return (p1==p2)?EOF:buf[p1++];
}
char cp;
template<class T>inline void rd(T &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
namespace Greedy{
int cot,v[N],mn[N],mx,num,bel[N];
vector<int>hv[N];
bool typ[N];
void sol()
{
int i,j,k,dlt=0,ss,rr;mn[0]=n+1;mx=0;
for(i=1;i<=n;++i) v[i]=a[i];
sort(v+1,v+n+1);num=unique(v+1,v+n+1)-v-1;
for(i=1;i<=n;++i) a[i]=lower_bound(v+1,v+n+1,a[i])-v;
for(i=1;i<=n;++i) mn[i]=min(mn[i-1],a[i]);
for(i=n;i>1;--i){mx=max(mx,a[i]);dlt=max(dlt,v[mx]-v[mn[i-1]]);}
for(mx=0,i=n;i>1;--i){
mx=max(mx,a[i]);
if(dlt==v[mx]-v[mn[i-1]] && (!bel[mx])){
bel[mx]=bel[mn[i-1]]=++cot;typ[mx]=true;
}
}
for(i=1;i<=n;++i) if(bel[a[i]]) hv[bel[a[i]]].pb(typ[a[i]]);
for(j=1;j<=cot;++j){
k=hv[j].size();mx=ss=rr=0;
for(i=dlt=0;i<k;++i){
if(hv[j][i]) {ss++;if(ss>0) ss=0,mx++;rr++;}
else ss--;
}
ans+=(rr-mx);
}
printf("%d",ans);
}
}
int main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
int i,j,x,y;
rd(n);
for(i=1;i<=n;++i) rd(a[i]);
Greedy::sol();
fclose(stdin);fclose(stdout);
return 0;
}
*permutation
网络流题终究做不出来。。。
这道题用到了 最大权闭合子图 和 最小割“切糕”模型 的思想:
发现对于 上的每条路径,必然是不选->选->不选。
拆点
,割三条边分别表示这个点不同的状态(在选择路径前/中/后)。
对于
中的所有边
,需要强制
的状态
的状态,所以连边
(“切糕”模型,强制相对顺序)。
对于每个点三条割边贡献的处理,采用最大权闭合子图的思想——若 ,则连边 ,否则连边 。
最小割
#include<bits/stdc++.h>
#define pb push_back
#define gc getchar
using namespace std;
const int N=1010,M=50040,inf=0x7f7f7f7f;
typedef long long ll;
typedef double db;
int n,m,a[N],s[N],S,T,d[N],dep[N],ans;
int head[N],to[M],nxt[M],w[M],tot=1;
inline void lk(int u,int v,int vv)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;
}
queue<int>que;
inline bool bfs()
{
memset(dep,0xff,sizeof(int)*(T+2));
dep[S]=0;int i,j,x;que.push(S);
for(;!que.empty();){
x=que.front();que.pop();
for(i=head[x];i;i=nxt[i]){
j=to[i];if((!w[i])|| (dep[j]!=-1)) continue;
dep[j]=dep[x]+1;que.push(j);
}
}
return (dep[T]!=-1);
}
int dfs(int x,int f)
{
if(x==T) return f;
int i,j,ss=0,res;
for(i=head[x];i;i=nxt[i]){
j=to[i];if((!w[i])||(dep[j]!=dep[x]+1)) continue;
res=dfs(j,min(f-ss,w[i]));if(!res) continue;
w[i]-=res;w[i^1]+=res;ss+=res;if(ss==f) return ss;
}
if(!ss) dep[x]=-1;
return ss;
}
char cp;
template<class T>inline void rd(T &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
int main(){
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
int i,j,x,y;
rd(n);rd(m);T=n+n+1;
for(i=1;i<=n;++i){
rd(x);
if(x>0) lk(S,i,x),lk(i+n,T,x),ans+=x;
else lk(i,i+n,-x);
}
for(i=1;i<=m;++i){
rd(x);rd(y);lk(x,y,inf);lk(x+n,y+n,inf);
}
for(;bfs();) ans-=dfs(S,inf);
printf("%d",ans);
fclose(stdin);fclose(stdout);
return 0;
}
*swap
设原串 长度为 ,下标从1开始( )
首先解决字符串合法的问题:
每次删去任意一对相邻的相同字符,设
操作完毕后变为
,若
为空串,则
合法。
于是可以栈维护 的 ,加入和删除一个字符都是 的(若加入的字符和上一个字符相同,则一起删去)。
字符集 ,可以枚举交换的两个字符 :
考虑分治,处理到区间 时,分别枚举 的位置 中, 的位置 中:
要求合并后合法,故 。
考虑同时处理出 前缀后缀的哈希,在上述 过程中,相当于二分查找 和 的最长公共后缀。
复杂度
细节:
- 枚举 的时候处理出所有情况的哈希值装在桶里,枚举 时用翻转串的哈希值加上对应的桶的值即可。
- 字符集太小,要用双哈希,而且膜了std发现双哈希还不够,要用 级别的模数!还要高精乘!
- 代码技巧丰富,可以细细品味一下。
STD Orz
#include<bits/stdc++.h>
typedef long long ll;
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define sc second
#define pb push_back
const int N=1e5+10;
const ll p1=1000000000000000003ll,p2=1000000000000000009ll;
using namespace std;
int n;ll ans;
char v[N];pll pw[N];
inline ll mul(ll a,ll b,ll p)
{
ll d=(a*b-(ll)((long double)a/p*b+(1e-8))*p);
return d<0?d+p:d;
}
inline ll ad(ll x,ll y,ll p){x+=y;return x>=p?x-p:x;}
inline ll dc(ll x,ll y,ll p){x-=y;return x<0?x+p:x;}
inline pll operator *(pll a,ll b){return mkp(a.fi*b%p1,a.sc*b%p2);}
inline pll operator +(pll a,ll b){return mkp(ad(a.fi,b,p1),ad(a.sc,b,p2));}
inline pll operator +(pll a,pll b){return mkp(ad(a.fi,b.fi,p1),ad(a.sc,b.sc,p2));}
inline pll operator -(pll a,pll b){return mkp(dc(a.fi,b.fi,p1),dc(a.sc,b.sc,p2));}
inline pll operator *(pll a,pll b){return mkp(mul(a.fi,b.fi,p1),mul(a.sc,b.sc,p2));}
struct HS{
int pos,sz;
vector<char>s;
vector<pll>a,b;
inline void init(int x)
{
pos=x;s.resize(1);a.resize(1);b.resize(1);
sz=0;s[0]=0;a[0]=b[0]=mkp(0,0);
}
inline void ins(char c)
{
if(s[sz]==c) {s.resize(sz);a.resize(sz);b.resize(sz);sz--;}
else{s.pb(c);a.pb((a[sz]*7)+(c-'a'+1));b.pb((b[sz]+(pw[sz]*(c-'a'+1))));sz++;}
}
//正向加
//反向加2次可以抵消(l->r + r->l = empty) 所以没有另外的撤回操作
inline void nt(int x)
{
for(;pos>x;) ins(v[pos--]);
for(;pos<x;) ins(v[++pos]);
}
inline void tn(int x)
{
for(;pos>x;) ins(v[--pos]);
for(;pos<x;) ins(v[pos++]);
}
inline pll fd(int x){return a[sz]-(pw[x]*a[sz-x]);}
}a,b,c;
inline int cal(int x,int y){return x*2+y-(y>x);}
inline pll meg(HS a,char c,HS b)
{
a.ins(c);int l=0,r=min(a.sz,b.sz),sim=0,mid;
for(;l<=r;){mid=(l+r)>>1;(a.fd(mid)==b.fd(mid))?(l=(sim=mid)+1):(r=mid-1);}
return (pw[b.sz-sim]*a.a[a.sz-sim])+b.b[b.sz-sim];
}
map<pll,int>w[6];
void sol(int l,int r)
{
if(l==r) return;
int i,j,mid=(l+r)>>1;
a.nt(mid-1);c.init(mid+1);
//注意c是倒着加的
for(i=mid;;){
for(j=0;j<3;++j) if(v[i]!='a'+j)
w[cal(v[i]-'a',j)][meg(a,'a'+j,c)]++;
if(i==l) break;
i--;a.nt(i-1);c.tn(i+1);
}
b.tn(mid+2);c.init(mid);
for(i=mid+1;;){
for(j=0;j<3;++j) if(v[i]!='a'+j)
ans+=w[cal(j,v[i]-'a')][meg(b,'a'+j,c)];//reverse
if(i==r) break;
i++;b.tn(i+1);c.nt(i-1);
}
for(i=0;i<6;++i) w[i].clear();
sol(l,mid);sol(mid+1,r);
}
int main(){
freopen("swap.in","r",stdin);
freopen("swap.out","w",stdout);
pw[0]=mkp(1,1);
scanf("%s",v+1);n=strlen(v+1);
for(int i=1;i<=n;++i) pw[i]=pw[i-1]*7;//*13/17 要用快速乘,会T
a.init(0);b.init(n+1);
sol(1,n);
printf("%lld",ans);
return 0;
}
总结
T1切的太慢
T2网络流永远都不会建模,给跪了,需要非常熟练地掌握和运用各种模型
T3没有时间想了,代码十分巧妙,我的哈希姿势不熟练估计也打不出来(点对分治——很经典的套路,很妙)
我的思维还是有问题,举一反三能力太差,或者是对模型理解不够深入
STO llppdd:“T2是真的傻”“会最大权闭合子图不是就秒想T2了吗?”