求数据卡掉该题不拆点的做法

P2766 最长不下降子序列问题

hkr04 @ 2020-03-28 13:50:04

不拆点已A,有可能是数据过弱。
图示例子是一种卡掉的情况,但是我好像不知道怎么构造出这样的数据。

代码:

#include <cstdio>
#include <cstring>
const int maxn=500+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
int a[maxn],f[maxn],dep[maxn];
int cur[maxn],head[maxn],to[maxm],nxt[maxm],val[maxm];
int tot=1,cnt=0;
int n,s,t;
struct Queue
{
    int a[maxn<<1];
    int l,r;
    Queue() {l=1,r=0;}
    void push(int x) {a[++r]=x;}
    void pop() {l++;}
    int front() {return a[l];}
    bool empty() {return l>r;}
}q;

int min(int x,int y) {return x<y?x:y;}
int max(int x,int y) {return x>y?x:y;}
void add(int u,int v,int w)
{
    nxt[++tot]=head[u];
    head[u]=tot;
    to[tot]=v;
    val[tot]=w;
}
bool bfs()
{
    memset(dep, 0x3f, sizeof(dep));
    dep[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for (int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if (val[i]&&dep[v]>dep[u]+1)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return dep[t]!=INF;
}
int dfs(int u,int minf)
{
    if (u==t||!minf)
        return minf;

    int used=0;
    for (int &i=cur[u];i;i=nxt[i])
    {
        int v=to[i];
        if (val[i]&&dep[v]==dep[u]+1)
        {
            int flow=dfs(v, min(minf-used, val[i]));
            if (!flow)
                continue;
            used+=flow;
            val[i]-=flow;
            val[i^1]+=flow;
            if (used==minf)
                break;
        }
    }
    return used;
}
int main()
{
    scanf("%d",&n);
    s=0,t=n+1;
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<=n;i++)
        f[i]=1;
    int sum=1;
    for (int i=1;i<=n;i++)
        for (int j=i-1;j>=1;j--)
            if (a[j]<=a[i])
                f[i]=max(f[i], f[j]+1);
    for (int i=1;i<=n;i++)
        sum=max(sum, f[i]);
    if (sum==1)
    {
        printf("%d\n%d\n%d\n",sum,n,n);
        return 0;
    }
    printf("%d\n",sum);
    for (int i=1;i<=n;i++)
    {
        if (f[i]==1)
            add(s, i, 1),add(i, s, 0);
        if (f[i]==sum)
            add(i, t, 1),add(t, i, 0);
        for (int j=i+1;j<=n;j++)
            if (a[i]<=a[j]&&f[i]+1==f[j])
                add(i, j, 1),add(j, i, 0);
    }
    int ans=0;
    while(bfs())
    {
        for (int i=s;i<=t;i++)
            cur[i]=head[i];
        ans+=dfs(s, INF);
    }
    printf("%d\n",ans);
    ans=0;
    for (int i=2;i<=tot;i++)
    {
        if (i&1)
            val[i]=0;
        else
            val[i]=(to[i]==1&&to[i^1]==s)||(to[i]==t&&to[i^1]==n)?INF:1;
    }
    while(bfs())
    {
        for (int i=s;i<=t;i++)
            cur[i]=head[i];
        ans+=dfs(s, INF);
    }
    printf("%d\n",ans);
    return 0;
}

by HearTheWindSing @ 2020-03-28 13:50:18

%%%


by 随情英 @ 2020-03-28 13:54:04

一个中间点,有多条出边和入边,就行了


by hkr04 @ 2020-03-28 13:56:05

我知道拆点可以限制点的使用次数,只是很好奇到底能不能卡掉这样的做法。
显然拆点可以避免掉最终3用两次的情况。


by hkr04 @ 2020-03-28 13:56:55

@随情英 我明白并已举出例子,现在我想要这样的数据


by Smile_Cindy @ 2020-03-28 14:14:10

@hkr04 数据来了

5
2 1 3 5 4

by hkr04 @ 2020-03-28 14:31:49

@Alpha 感谢!


by hkr04 @ 2020-03-28 14:32:53

@Alpha 但是第一问就错了呀


by hkr04 @ 2020-03-28 14:35:50

@Alpha 题解区跑出来的是

3
1
1

错误答案:

3
2
2

by Smile_Cindy @ 2020-03-28 15:28:02

@hkr04 手残,我的stdout是手写的。


by Smile_Cindy @ 2020-03-28 15:29:03

真正的stdout:

3
1
1

|