给定正整数序列x1,..... , xn 。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长
度为s的递增子序列。
第1 行有1个正整数n,表示给定序列的长度。接
下来的1 行有n个正整数x1.....xn 。
第1 行是最长递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
4
3 6 2 5
2
2
3
注意:虽然题目是最长递增子序列,但是code vs上的测试数据是按最长不下降子序列来的
题解:
1. dp求最长不下降子序列,不用多说
2.建图(看程序,比较好理解),跑最大流
3.与2相似,因为1,n可以多次使用,所以只需加大源点到1的容量和n到汇点的容量即可
另外此题还是需要拆点,拆成的两个点之间连一条容量为1的边,因为只有这样才能控制每个点之用一次
#include
#include
#include
#include
using namespace std;
int point[2100],next[2000003],v[2000003],remain[2000003];
int deep[2100],cur[2100],num[2100],n,m,tot,ans,laste[2100];
int a[2100],f[2100];
const int inf=1e9;
void add(int x,int y,int z)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
int adde(int s,int t)
{
int now=t,minn=inf;
while (now!=s)
{
minn=min(minn,remain[laste[now]]);
now=v[laste[now]^1];
}
now=t;
while (now!=s)
{
remain[laste[now]]-=minn;
remain[laste[now]^1]+=minn;
now=v[laste[now]^1];
}
return minn;
}
void bfs(int s,int t)
{
for (int i=s;i<=t;i++)
deep[i]=t+2;
deep[t]=0;
queue p;
p.push(t);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (deep[v[i]]==t+2&&remain[i^1])
{
deep[v[i]]=deep[now]+1;
p.push(v[i]);
}
}
}
int isap(int s,int t)
{
int flow=0,now=s;
bfs(s,t);
memset(num,0,sizeof(num));
for (int i=s;i<=t;i++) num[deep[i]]++;
for (int i=s;i<=t;i++) cur[i]=point[i];
while (deep[s]<=t)
{
if (now==t)
{
flow+=adde(s,t);
now=s;
}
bool hasfind=false;
for (int i=cur[now];i!=-1;i=next[i])
{
if (deep[v[i]]+1==deep[now]&&remain[i])
{
hasfind=true;
cur[now]=i;
laste[v[i]]=i;
now=v[i];
break;
}
}
if (!hasfind)
{
int minn=t;
for (int i=point[now];i!=-1;i=next[i])
if (remain[i])
minn=min(minn,deep[v[i]]+1);
if (!--num[deep[now]]) break;
deep[now]=minn;
num[minn]++; cur[now]=point[now];
if (now!=s)
now=v[laste[now]^1];
}
}
return flow;
}
void solve1()
{
for (int i=1;i<=n;i++)
{
if (f[i]==1) add(0,i,1);
if (f[i]==ans) add(i+n,2*n+1,1);
add(i,i+n,1);
}
for (int i=2;i<=n;i++)
{
for (int j=1;j=a[j])
add(j+n,i,1);
}
if (ans==1) printf("%d\n",n);
else
printf("%d\n",isap(0,2*n+1));
}
void solve2()
{
tot=-1; memset(next,-1,sizeof(next)); memset(point,-1,sizeof(point));
for (int i=1;i<=n;i++)
{
int v=1;
if (i==1||i==n) v=inf;
if (f[i]==1) add(0,i,v);
if (f[i]==ans) add(i+n,2*n+1,v);
add(i,i+n,v);
}
for (int i=2;i<=n;i++)
{
for (int j=1;j=a[j])
add(j+n,i,1);
}
if (ans==1) printf("%d\n",n);
else
printf("%d\n",isap(0,2*n+1));
}
int main()
{
tot=-1; memset(next,-1,sizeof(next)); memset(point,-1,sizeof(point));
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
f[1]=1;
for (int i=2;i<=n;i++)
{
for (int j=1;j