2019CCPC哈爾濱Artful Paintings(二分+差分約束)

2019CCPC哈爾濱Artful Paintings(二分+差分約束)

題目鏈接:傳送門

思路:

這題現場賽的時候TLE了,賽後才發現spfa可以剪枝,而且還缺少一約束。

我們假設答案是k,那麼k+1也可行,所以可行性具有單調性。設函數S( i )爲前 i 個cube畫的個數。

那麼有約束

  • 1S(i)S(i1)01\ge S(i)-S(i-1)\ge0
  • 對於第一種條件,S(r)S(l1)kS(r)-S(l-1)\ge k
  • 對於第二種條件,S(n)S(r)+S(l1)kS(n)-S(r)+S(l-1)\ge k

因爲對於第二種條件, S(n)S(n)的值不確定,所以不能直接建立差分約束圖。但是因爲可行性對於S(n)S(n)的值有單調性,所以我們二分S(n)S(n) 的值,就能用差分約束系統來check 的可行性,從而求出S(n)S(n)的最小值。

但是要注意的是,假設此時令S(n)=wS(n)=w,然後檢查可行性的時,需要增加約束S(n)=wS(n)=w。另外沒有剪紙的差分約束是會TLE的(根據圖的性質進行剪紙),但是建圖(建最短圖的話)後我們發現所有點都有到0有一條費用爲0的路徑,所以一旦存在某個u 使得 dis[u]<0dis[u]<0,那麼必定有負環。

代碼:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=3e3+10;
const int inf=0x3f3f3f3f;
struct Node
{
    int l,r,k;
} q1[N],q2[N];
int n,k1,k2;
int dis[N],in[N];//距離
struct Edge{
    int to,w;
    Edge() {};
    Edge(int to,int w):to(to),w(w) {}
};
vector<Edge> g[N];//鄰接表
bool book[N];//標記是否夠在隊列
bool spfa(int s,int n)//源點爲s,共有(0..n)n個點,求最短路
{
    //有負環返回true,無負環返回false
    queue<int> qe;
    fill(dis,dis+n,inf);
    fill(in,in+n,0);
    fill(book,book+n,false);
    dis[s]=0;
    qe.push(s);
    book[s]=true;
    while(!qe.empty())
    {
        int u=qe.front();
        qe.pop();
        in[u]++;
        book[u]=false;
        if(dis[u] < 0 ) return true;
        if(in[u] > n) return true;
        for(Edge &e:g[u])
        {
            int v=e.to,w=e.w;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(!book[v])
                {
                    book[v]=true;
                    qe.push(v);
                }
            }
        }
    }
//    puts("no circle");
    return false;
}
bool check(int mv)//無環返回true
{
//    printf("mv:%d\n",mv);
    for(int i=0; i<=n; ++i) g[i].clear();
    for(int i=1; i<=k1; ++i)
    {
        int u=q1[i].r,v=q1[i].l-1,w=-q1[i].k;
        g[u].push_back(Edge(v,w));
    }
    for(int i=1;i<=n;++i){
         g[i].push_back(Edge(i-1,0));
         g[i-1].push_back(Edge(i,1));
    }
    for(int i=1; i<=k2; ++i)
    {
        int u=q2[i].l-1,v=q2[i].r,w=mv-q2[i].k;
        g[u].push_back(Edge(v,w));
    }
    g[0].push_back(Edge(n,mv));
    g[n].push_back(Edge(0,-mv));
    return !spfa(0,n+1);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&k1,&k2);
        for(int i=1; i<=k1; ++i)
            scanf("%d%d%d",&q1[i].l,&q1[i].r,&q1[i].k);
        for(int i=1; i<=k2; ++i)
            scanf("%d%d%d",&q2[i].l,&q2[i].r,&q2[i].k);
        int ans=-1,l=0,r=n;
        while(l<=r)
        {
            int m=(l+r)/2;
            if(check(m))
            {
                ans=m;
                r=m-1;
            }
            else
                l=m+1;
        }
        printf("%d\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章