部分分作法不少,但每想出來一個也就多5~10分。正解還不會,下面是各類部分分作法:html
Subtask 1:k=1算法
LCS長度最長爲1,也就是說不存在j>i和a[j]>a[i]同時成立。顯然就是一個LDS,樹狀數組直接求便可。數組
Subtask 2:k=2網絡
最多兩個,也就是能夠由兩個LCS拼起來,f[i][j]表示第一個LCS以i結尾,第二個以j結尾的方案數,轉移顯然。優化
Subtask 3:k=2spa
樹狀數組優化DP,複雜度由$O(n^3)$降爲$O(n^2 \log n)$code
Subtask 4,5:B<=8htm
DP套DP:https://www.cnblogs.com/clnchanpin/p/7357564.htmlblog
通常與「子序列」同時出現,如最長上升自序列,最長公共自序列等。get
Subtask 6,7:
一個顯然的定理:一個序列的LCS最大爲k意味着這個序列最少能夠由k個不相交的LDS組成。
考慮網絡流,下面(a,b)表示容量爲a,費用爲b的邊。
拆點,in[x]向out[x]連(1,-1)的邊,每次和下一個小於這個數的位置連(1,0)的邊,增設源匯,最多增廣k次便可。
$O(Kn^3)$
Subtask 8,9:
上面的方法點數爲$n$,邊數爲$n^2$,啓發咱們用線段樹優化建圖。
這裏用樹狀數組就好了。
點數$n\log n$,邊數$n\log n$。
$O(K(n\log n)^2)$
Subtask 10,11,12:
Johnson多源最短路算法:
傳統的Floyd是$O(n^3)$的,已經很優秀了。可是若是咱們對每一個點跑一次Dijkstra,能夠獲得$O(n^2\log m)$這個更好的複雜度。
可是Dijkstra不能跑有負權邊的狀況。
考慮增設超級源S並向每一個點連長度爲0的邊,而後跑單源最短路,接着將每條邊(u,v,w)改爲(u,v,w+(dis[u]-dis[v])),其中dis[u]表示S到u的最短路。
這樣跑Dijkstra就是正確的了,轉移的時候記錄pre方便最後求出最短路長度。
不瞭解如何運用到這道題上。
優化:能夠直接用數組代替堆下降複雜度。
Subtask 13~20:
徹底不理解的楊氏矩陣理論。
不斷分析將複雜度依次降爲:$O(n^2\log n+Q\log n)$,$O(n\sqrt{n}\log n)$,$O(n\sqrt{n\log n})$。
附:樹狀數組+網絡流代碼(15pts)
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define rep(i,l,r) for (int i=(l); i<=(r); i++) using namespace std; const int N=100010; int x,y,fir[N],pre[N],a[N],b[N],inq[N],dis[N],n,m,cnt=1; int in[N],out[N],ans[N],BIT[N],S,T,cost,lim,obt,tot; struct edge{ int to,nxt,f,c; edge () {} edge (int x,int y,int z,int l){ to=y; nxt=fir[x]; f=z; c=l; fir[x]=cnt; } }e[6*N]; void add(int x,int y,int z,int l){ e[++cnt]=edge(x,y,z,l); e[++cnt]=edge(y,x,0,-l); } bool spfa(){ int i,x; queue<int> q; for(i=1;i<=T;i++) dis[i]=1; dis[S]=0; q.push(S); while(!q.empty()){ x=q.front(); q.pop(); for(i=fir[x];i;i=e[i].nxt) if(e[i].f&&dis[e[i].to]>dis[x]+e[i].c){ dis[e[i].to]=dis[x]+e[i].c; pre[e[i].to]=i; if(!inq[e[i].to]) q.push(e[i].to),inq[e[i].to]=1; } inq[x]=0; } return dis[T]!=1; } int aug(){ int x,flow=1e9; for(x=T;x!=S;x=e[pre[x]^1].to) flow=min(flow,e[pre[x]].f); for(x=T;x!=S;x=e[pre[x]^1].to) cost+=e[pre[x]].c*flow,e[pre[x]].f-=flow,e[pre[x]^1].f+=flow; return flow; } int dinic(){ int res=0; while(spfa()) res+=aug(); return res; } void modify(int p,int x){ for(;x<=obt;x+=x&-x){ tot++; if(BIT[x]) add(tot,BIT[x],n,0); add(tot,p,1,0); BIT[x]=tot; } } void ask(int p,int x){ for (;x;x-=x&-x) if (BIT[x]) add(p,BIT[x],1,0); } int main(){ freopen("lis.in","r",stdin); freopen("lis.out","w",stdout); scanf("%d%d",&n,&m); if (n>100) { rep(i,1,m) printf("0\n"); return 0; } rep(i,1,n) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); obt=unique(b+1,b+n+1)-b-1; rep(i,1,n) a[i]=lower_bound(b+1,b+obt+1,a[i])-b; rep(i,1,n) in[i]=i,out[i]=i+n,add(in[i],out[i],1,-1); tot=2*n; for (int i=n;i;i--) ask(out[i],a[i]),modify(in[i],a[i]); S=tot+1; T=S+1; rep(i,1,n) add(S,in[i],1,0),add(out[i],T,1,0); cost=lim=0; while(spfa()) aug(),ans[++lim]=-cost; while(m--) scanf("%d%d",&x,&y),printf("%d\n",ans[min(y,lim)]); return 0; }