顯示具有 BZOJ 標籤的文章。 顯示所有文章
顯示具有 BZOJ 標籤的文章。 顯示所有文章

2018年3月13日 星期二

(BZOJ) 3993: [SDOI2015]星际战争

http://www.lydsy.com/JudgeOnline/problem.php?id=3993

最近真的一直在耍智障>< 一些很簡單的題目都想不太出來><

對答案作二分搜,注意到每個激光武器的攻擊量是一樣的。

所以,假設現在搜到mid,則:源點s --> 每個激光武器,流量 = t * b[i]

每個機器人 --> 匯點t,流量 = a[i]

如果激光武器 i 可以攻擊 機器人 j ,則 i-->j ,流量= a[i]

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;

#define SZ(x) ((int)(x).size())

typedef long double ld;
const ld eps = 1e-9;

bool eq(ld a,ld b)
{
    return fabs(a-b) <= eps;
}

struct Dinic
{
    static const int N = 106;
    struct Edge
    {
        int to;
        ld cap;
        int rev;
        Edge(){}
        Edge(int _to,ld _cap,int _rev)
        {
            to = _to;
            cap = _cap;
            rev = _rev;
        }
    };
    vector<Edge> G[N];
    void add_edge(int from,int to,ld cap)
    {
        G[from].push_back(Edge(to,cap,SZ(G[to])));
        G[to].push_back(Edge(from,0,SZ(G[from])-1));
    }
    int n,s,t;
    void init(int _n,int _s,int _t)
    {
        n = _n;
        s = _s;
        t = _t;
        for (int i=0;n>=i;i++)
        {
            G[i].clear();
        }
    }
    int level[N],iter[N];
    void BFS()
    {
        memset(level,-1,sizeof(level));
        level[s]=0;
        queue<int> que;
        que.push(s);
        while (!que.empty())
        {
            int t=que.front();
            que.pop();
            for (int i=0;SZ(G[t])>i;i++)
            {
                Edge e=G[t][i];
                if (!eq(e.cap,0) && level[e.to] == -1)
                {
                    level[e.to] = level[t] +1;
                    que.push(e.to);
                }
            }
        }
    }
    ld dfs(int now, ld flow)
    {
        if (now == t) return flow;
        for (int &i=iter[now];SZ(G[now])>i;i++)
        {
            Edge &e = G[now][i];
            if (!eq(e.cap,0) && level[e.to] == level[now] + 1)
            {
                ld ret = dfs(e.to,min(flow,e.cap));
                if (!eq(ret,0))
                {
                    e.cap -= ret;
                    G[e.to][e.rev].cap += ret;
                    return ret;
                }
            }
        }
        return 0;
    }
    ld flow()
    {
        ld ret=0;
        while (true)
        {
            BFS();
            if (level[t] == -1) break;
            memset(iter,0,sizeof(iter));
            ld tmp=0;
            while (!eq(0, (tmp = dfs(s,1e20)) ))
            {
                ret += tmp;
            }
        }
        return ret;
    }
} kirino;

const int N = 56;

int a[N];
int b[N];
int can[N][N];

int main ()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for (int i=1;n>=i;i++)
    {
        scanf("%d",&a[i]); //robot blood
    }
    for (int i=1;m>=i;i++)
    {
        scanf("%d",&b[i]); //weapon cost
    }
    for (int i=1;m>=i;i++)
    {
        for (int j=1;n>=j;j++)
        {
            scanf("%d",&can[i][j]);  //weapon i can beat robot j
        }
    }
    ld L=0,R=1e10;
    int cnt=100;
    int s=0,t=n+m+1;
    while (cnt--)
    {
        ld mid = (L+R)/2;
        kirino.init(t,s,t);
        for (int i=1;m>=i;i++)
        {
            kirino.add_edge(s,i,b[i]*mid);
        }
        ld tot=0;
        for (int i=1;n>=i;i++)
        {
            kirino.add_edge(i+m,t,a[i]);
            tot += a[i];
        }
        for (int i=1;m>=i;i++)
        {
            for (int j=1;n>=j;j++)
            {
                if (can[i][j])
                {
                    kirino.add_edge(i,j+m,a[j]);
                }
            }
        }
        ld ret = kirino.flow();
        if (eq(ret,tot)) R=mid;
        else L=mid;
    }
    double ans=R;
    printf("%.10f\n",ans);
}

(BZOJ) 4514: [Sdoi2016]数字配对

http://www.lydsy.com/JudgeOnline/problem.php?id=4514

先把數字分成兩類:質因數各數有奇數個的或有偶數個的

這樣一來,圖就是二分圖了。

之後再用min cost max flow亂搞即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

typedef long long LL;
typedef pair<LL,LL> pii;

#define SZ(x) ((int)(x).size())

struct Kirino
{
    static const int N = 206;
    struct Edge
    {
        LL to,cap,rev,cost;
        Edge(LL _to,LL _cap,LL _rev,LL _cost)
        {
            to = _to;
            cap = _cap;
            rev = _rev;
            cost = _cost;
        }
    };
    vector<Edge> G[N];
    void add_edge(int from,int to,LL cap,LL cost)
    {
        G[from].push_back(Edge(to,cap,SZ(G[to]),cost));
        G[to].push_back(Edge(from,0,SZ(G[from])-1,-cost));
    }
    int n,s,t;
    void init(int _n,int _s,int _t)
    {
        n=_n;
        s=_s;
        t=_t;
        for (int i=0;n>=i;i++)
        {
            G[i].clear();
        }
    }
    LL dis[N];
    int pre[N],pre_id[N];
    bool in_que[N];
    pii sagiri()
    {
        LL flow=0,cost=0;
        LL INF = (1LL<<40);
        while (true)
        {
            memset(in_que,0,sizeof(in_que));
            fill(dis,dis+n+1,INF);
            queue<int> que;
            que.push(s);
            dis[s]=0;
            while (!que.empty())
            {
                int t=que.front();
                que.pop();
                in_que[t] = false;
                for (int i=0;SZ(G[t])>i;i++)
                {
                    Edge e=G[t][i];
                    if (e.cap > 0 && dis[e.to] > dis[t] + e.cost)
                    {
                        dis[e.to] = dis[t] + e.cost;
                        pre[e.to] = t;
                        pre_id[e.to] = i;
                        if (!in_que[e.to])
                        {
                            in_que[e.to] = 1;
                            que.push(e.to);
                        }
                    }
                }
            }
            if (dis[t] == INF) break;
            LL mn_flow = INF;
            for (int i=t;i!=s;i=pre[i])
            {
                mn_flow = min( mn_flow, G[ pre[i] ][ pre_id[i] ].cap  );
            }
            if (mn_flow*dis[t]+cost > 0)
            {
                int L=0,R=mn_flow; //L is the answer
                while (R-L != 1)
                {
                    int mid=(L+R)>>1;
                    if (mid*dis[t] + cost > 0) R=mid;
                    else L=mid;
                }
                flow += L;
                cost += L*dis[t];
                break;
            }
            flow += mn_flow;
            cost += mn_flow*dis[t];
            for (int i=t;i!=s;i=pre[i])
            {
                G[ pre[i] ][ pre_id[i] ].cap -= mn_flow;
                G[ i ][ G[ pre[i] ][ pre_id[i] ].rev ].cap += mn_flow;
            }
        }
        return make_pair(flow,cost);
    }
} meruru;

const int N = 206;

int a[N],b[N];
LL c[N];

vector<int> v[N];

vector<int> get_p(LL x)
{
    vector<int> ret;
    for (int i=2;i*i<=x;i++)
    {
        while (x%i==0)
        {
            ret.push_back(i);
            x/=i;
        }
    }
    if (x != 1) ret.push_back(x);
    return ret;
}

int main()
{
    int n;
    scanf("%d",&n);
    int INF = 1000000007;
    for (int i=1;n>=i;i++)
    {
        scanf("%d",&a[i]);
        v[i] = get_p(a[i]);
    }
    for (int i=1;n>=i;i++)
    {
        scanf("%d",&b[i]);
    }
    for (int i=1;n>=i;i++)
    {
        scanf("%lld",&c[i]);
    }
    int s=0,t=n+1;
    meruru.init(t,s,t);
    for (int i=1;n>=i;i++)
    {
        if (SZ(v[i])%2==1)
        {
            meruru.add_edge(s,i,b[i],0);
        }
        else
        {
            meruru.add_edge(i,t,b[i],0);
        }
        for (int j=1;n>=j;j++)
        {
            if (i==j) continue;
            if (a[i]%a[j] == 0 && SZ(v[i]) - SZ(v[j]) == 1)
            {
                int ii=i,jj=j;
                if (SZ(v[ii])%2 == 0) swap(ii,jj);
                meruru.add_edge(ii,jj,INF,-c[ii]*1LL*c[jj]);
            }
        }
    }
    pii ret=meruru.sagiri();
    printf("%lld\n",ret.first);
}

(BZOJ) 1070: [SCOI2007]修车

http://www.lydsy.com/JudgeOnline/problem.php?id=1070

超神min cost max flow題。

可以想像說:假設第j個人先後修理車的順序是x_1, x_2, ......, x_t,那,a[x_1][j]的貢獻就是a[x_1][j] * t, a[x_2][j]就是a[x_2][j] * (t-1) ......

有了上面(?)的想法後,就可以寫flow了~

#include <iostream>
#include <cstdio>
#include <utility>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

#define int long long
typedef pair<int,int> pii;

struct Flow
{
    static const int N = 100006;
    struct Edge
    {
        int to,cap,rev,cost;
        Edge(){}
        Edge(int _to,int _cap,int _rev,int _cost)
        {
            to = _to;
            cap = _cap;
            rev = _rev;
            cost = _cost;
        }
    };
    vector<Edge> G[N];
    #define SZ(x) ((int)(x).size())
    void add_edge(int from,int to,int cap,int cost)
    {
        G[from].push_back(Edge(to,cap,SZ(G[to]),cost));
        G[to].push_back(Edge(from,0,SZ(G[from])-1,-cost));
    }
    int n,s,t;
    void init(int _n,int _s,int _t)
    {
        n = _n;
        s = _s;
        t = _t;
        for (int i=0;n>=i;i++)
        {
            G[i].clear();
        }
    }
    int pre[N],pre_id[N];
    bool in_que[N];
    int dis[N];
    pii shooting_stars()
    {
        int flow=0,cost = 0;
        int INF = (1LL<<50);
        while (true)
        {
            memset(in_que,0,sizeof(in_que));
            fill(dis,dis+n+1,INF);
            queue<int> que;
            que.push(s);
            dis[s] = 0;
            while (!que.empty())
            {
                int t=que.front();
                que.pop();
                in_que[t] = false;
                for (int i=0;G[t].size()>i;i++)
                {
                    Edge e=G[t][i];
                    if (e.cap > 0 && dis[e.to] > dis[t] + e.cost)
                    {
                        dis[e.to] = dis[t] + e.cost;
                        pre[e.to] = t;
                        pre_id[e.to] = i;
                        if (!in_que[e.to])
                        {
                            in_que[e.to] = 1;
                            que.push(e.to);
                        }
                    }
                }
            }
            if (dis[t] == INF) break;
            int mn_flow = INF;
            for (int i=t;i!=s;i=pre[i])
            {
                mn_flow = min( mn_flow, G[ pre[i] ][ pre_id[i] ].cap );
            }
            flow += mn_flow;
            cost += mn_flow * dis[t];
            for (int i=t;i!=s;i=pre[i])
            {
                G[ pre[i] ][ pre_id[i] ].cap -= mn_flow;
                G[ i ][ G[ pre[i] ][ pre_id[i] ].rev ].cap += mn_flow;
            }
        }
        return make_pair(flow,cost);
    }
} sagiri;

const int N = 66;

int a[N][N];

int32_t main ()
{
    int m,n;
    scanf("%lld %lld",&m,&n);
    for (int i=1;n>=i;i++)
    {
        for (int j=1;m>=j;j++)
        {
            scanf("%lld",&a[i][j]);
        }
    }
    int s=0,t = 100002;
    sagiri.init(t,s,t);
    for (int i=1;n>=i;i++)
    {
        sagiri.add_edge(i,t,1,0);
    }
    int now = n+1;
    for (int i=1;m>=i;i++)
    {
        for (int j=1;n>=j;j++)
        {
            int tmp=now;
            now++;
            sagiri.add_edge(s,tmp,1,0);
            for (int k=1;n>=k;k++)
            {
                //i-th person fix k-th car at time j
                int _=now;
                sagiri.add_edge(tmp,_,1,a[k][i]*j);
                now++;
                sagiri.add_edge(_,k,1,0);
            }
        }
    }
    pii ret = sagiri.shooting_stars();
    printf("%.2f\n",ret.second*1.0/n);
}

2018年3月9日 星期五

(BZOJ) 1061: [Noi2008]志愿者招募 [神奇的 min cost max flow ]

http://www.lydsy.com/JudgeOnline/problem.php?id=1061

直接附題解連結:http://www.cnblogs.com/jianglangcaijin/p/3799759.html

好像跟 "單純形法" 有關><。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef pair<LL,LL> pii;

struct Flow
{
    static const int N = 20006;
    struct Edge
    {
        int to,rev;
        LL cap;
        LL cost;
        Edge(int _to,LL _cap,int _rev,LL _cost)
        {
            to = _to;
            cap = _cap;
            rev = _rev;
            cost = _cost;
        }
    };
    vector<Edge> G[N];
    #define SZ(x) ((int)(x).size())
    void add_edge(int from,int to,LL cap,LL cost)
    {
        G[from].push_back(Edge(to,cap,SZ(G[to]),cost));
        G[to].push_back(Edge(from,0,SZ(G[from])-1,-cost));
    }
    int n,s,t;
    void init(int _n,int _s,int _t)
    {
        n = _n;
        s = _s;
        t = _t;
        for (int i=0;n>=i;i++)
        {
            G[i].clear();
        }
    }
    int pre[N],pre_id[N];
    LL dis[N];
    bool in_que[N];
    pii flow()
    {
        LL flow=0,cost=0;
        LL INF = (1LL << 60);
        while (true)
        {
            queue<int> que;
            memset(in_que,0,sizeof(in_que));
            fill(dis,dis+n+1,INF);
            que.push(s);
            dis[s]=0;
            while (!que.empty())
            {
                int t=que.front();
                que.pop();
                in_que[t] = false;
                for (int id=0;G[t].size()>id;id++)
                {
                    Edge e = G[t][id];
                    if (e.cap > 0 && dis[e.to] > dis[t] + e.cost)
                    {
                        dis[e.to] = dis[t] + e.cost;
                        pre[e.to] = t;
                        pre_id[e.to] = id;
                        if (!in_que[e.to])
                        {
                            in_que[e.to] = 1;
                            que.push(e.to);
                        }
                    }
                }
            }
            //cout << "dis t = "<<
            if (dis[t] == INF) break;
            LL mn_flow = INF;
            for (int i=t;i!=s;i=pre[i])
            {
                mn_flow = min(mn_flow,G[ pre[i] ][ pre_id[i] ].cap);
            }
            flow += mn_flow;
            cost += mn_flow*dis[t];
            for (int i=t;i!=s;i=pre[i])
            {
                G[ pre[i] ][ pre_id[i] ].cap -= mn_flow;
                G[i][ G[ pre[i] ][ pre_id[i] ].rev ].cap += mn_flow;
            }
        }
        return make_pair(flow,cost);
    }
} solver;

LL d[10007];

int main ()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for (int i=1;n>=i;i++)
    {
        scanf("%lld",&d[i]);
    }
    int s=0,t=n+1;
    solver.init(t,s,t);
    for (int i=1;m>=i;i++)
    {
        int s,t,d;
        scanf("%d %d %d",&s,&t,&d);
        solver.add_edge(s,t+1,(1LL<<40),d);
    }
    for (int i=1;n+1>=i;i++)
    {
        LL tmp = d[i] - d[i-1];
        if (tmp >= 0) solver.add_edge(s,i,tmp,0);
        else solver.add_edge(i,t,-tmp,0);
        if (i>1) solver.add_edge(i,i-1,(1LL<<40),0);
    }
    printf("%lld\n",solver.flow().second);
}


2017年11月23日 星期四

(BZOJ) 4337: BJOI2015 树的同构

http://www.lydsy.com/JudgeOnline/problem.php?id=4337

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <utility>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
using namespace std;

#define LL   long long
#define ld   long double
#define pii  pair<int,int>
#define pLL  pair<LL,LL>
#define vint vector<int>
#define vLL  vector<LL>

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define F first
#define S second
#define MP make_pair
#define PB push_back

#define Si(x) scanf("%d",&(x));
#define Sii(x,y) scanf("%d %d",&(x),&(y));
#define Siii(x,y,z) scanf("%d %d %d",&(x),&(y),&(z));
#define Siiii(x,y,z,w) scanf("%d %d %d %d",&(x),&(y),&(z),&(w));
#define Siiiii(x,y,z,w,a) scanf("%d %d %d %d %d",&(x),&(y),&(z),&(w),&(a));
#define Siiiiii(x,y,z,w,a,b) scanf("%d %d %d %d %d %d",&(x),&(y),&(z),&(w),&(a),&(b));
#define SL(x) scanf("%lld",&(x));
#define SLL(x,y) scanf("%lld %lld",&(x),&(y));
#define SLLL(x,y,z) scanf("%lld %lld %lld",&(x),&(y),&(z));
#define SLLLL(x,y,z,w) scanf("%lld %lld %lld %lld",&(x),&(y),&(z),&(w));
#define SLLLLL(x,y,z,w,a) scanf("%lld %lld %lld %lld %lld",&(x),&(y),&(z),&(w),&(a));
#define SLLLLLL(x,y,z,w,a,b) scanf("%lld %lld %lld %lld %lld %lld",&(x),&(y),&(z),&(w),&(a),&(b));

#define Pi(x) printf("%d\n",(x));
#define Pii(x,y) printf("%d %d\n",(x),(y));
#define Piii(x,y,z) printf("%d %d %d\n",(x),(y),(z));
#define Piiii(x,y,z,w) printf("%d %d %d %d\n",(x),(y),(z),(w));
#define Piiiii(a,b,c,d,e) printf("%d %d %d %d %d\n",(a),(b),(c),(d),(e));
#define Piiiiii(a,b,c,d,e,f) printf("%d %d %d %d %d %d\n",(a),(b),(c),(d),(e),(f));
#define PL(x) printf("%lld\n",(x)*1LL);
#define PLL(x,y) printf("%lld %lld\n",(x)*1LL,(y)*1LL);
#define PLLL(x,y,z) printf("%lld %lld %lld\n",(x)*1LL,(y)*1LL,(z)*1LL);
#define PLLLL(x,y,z,w) printf("%lld %lld %lld %lld\n",(x)*1LL,(y)*1LL,(z)*1LL,(w)*1LL);
#define PLLLLL(a,b,c,d,e) printf("%lld %lld %lld %lld %lld\n",(a),(b),(c),(d),(e));
#define PLLLLLL(a,b,c,d,e,f) printf("%lld %lld %lld %lld %lld %lld\n",(a),(b),(c),(d),(e),(f));

#define Pi1(x) printf("%d",  (x));
#define PiL(x) printf("%lld",(x));
#define Pspace putchar(' ');
#define Pendl  puts("");

#define MEM0(x) memset( (x), 0, sizeof( (x) ) )
#define MEM1(x) memset( (x),-1, sizeof( (x) ) )
#define REP1(i,n)  for (int i = 1; (n) >= i ; ++i)
#define REP0(i,n)  for (int i = 0; (n) >  i ; ++i)
#define REP(L,R,k) for (int i = (L); (R) >= i; i+= (k) )

int myRnd(int L,int R) {
    return abs(( (rand()<<15)|rand() ) ) % (R-L+1) + L;
}

const int N = 56;

int rnd1[N];
int rnd2[N];

map<LL,int> mp[N];

int p[N];

vint G[N];

bool vis[N];
int cnt[N];

void dfs(int now,int depth) {
    vis[now] = 1;
    cnt[depth]++;
    for (int i=0;SZ(G[now])>i;i++) {
        int ii=G[now][i];
        if (vis[ii]) continue;
        dfs(ii,depth+1);
    }
}

int main () {
    srand(7122);
    REP0(i,N)
    {
        rnd1[i] = myRnd(0,(1LL<<28)-1);
        rnd2[i] = myRnd(0,(1LL<<28)-1);
    }
    int q;
    Si(q);
    REP1(i,q)
    {
        int n;
        Si(n);
        for (int i=1;n>=i;i++) {
            int x;
            scanf("%d",&x);
            if (x!=0) {
                G[x].PB(i);
                G[i].PB(x);
            }
        }
        LL now=0;
        for (int i=1;n>=i;i++) {
            MEM0(cnt);
            MEM0(vis);
            dfs(i,1);
            LL tmp=0;
            REP0(j,N)
            {
                if (cnt[j] == 0) continue;
                tmp += (rnd2[ cnt[j] ] * rnd1[j]);
            }
            now += tmp;
        }
        int ret=mp[n][now];
        if (ret == 0) {
            mp[n][now] = i;
            printf("%d\n",i);
        }
        else {
            printf("%d\n",ret);
        }
        for (int i=0;n>=i;i++) {
            G[i].clear();
        }
    }
}