XJOI泡泡糖

给你一幅行数不超过5的总点数不超过1e5+5e4的网格图,每个点的点权在l到r之间(r<=10000),每条有边权,每条边的贡献为这条边的边权乘上这条边两端的点权的绝对值之差,最小化所有边的边权之和

题解写的很好,就不在赘述.
这题可以用状压,贪心,最小割,维护分段函数,线段树,线性规划分别得到不同的部分分.
最后对于决策确定,有维护修改和整体划分(分治)两种,值得借鉴考虑.

最小割方案间的性质

调代码要先想好,再写,考虑每个变量有怎样的影响,再决定如何定义.

%:pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;

namespace fastIO{
    #define BUF_SIZE 100005
    #define OUT_SIZE 100005
    #define ll long long
    //fread->read
    bool IOerror=0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend){
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1){IOerror=1;return -1;}
            //{printf("IO error!\n");system("pause");for (;;);exit(0);}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline void read(int &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(ll &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(double &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (ch=='.'){
            double tmp=1; ch=nc();
            for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
        }
        if (sign)x=-x;
    }
    inline void read(char *s){
        char ch=nc();
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
        *s=0;
    }
    inline void read(char &c){
        for (c=nc();blank(c);c=nc());
        if (IOerror){c=-1;return;}
    }
    //getchar->read
    inline void read1(int &x){
        char ch;int bo=0;x=0;
        for (ch=getchar();ch<'0'||ch>'9';ch=getchar())if (ch=='-')bo=1;
        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
        if (bo)x=-x;
    }
    inline void read1(ll &x){
        char ch;int bo=0;x=0;
        for (ch=getchar();ch<'0'||ch>'9';ch=getchar())if (ch=='-')bo=1;
        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
        if (bo)x=-x;
    }
    inline void read1(double &x){
        char ch;int bo=0;x=0;
        for (ch=getchar();ch<'0'||ch>'9';ch=getchar())if (ch=='-')bo=1;
        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
        if (ch=='.'){
            double tmp=1;
            for (ch=getchar();ch>='0'&&ch<='9';tmp/=10.0,x+=tmp*(ch-'0'),ch=getchar());
        }
        if (bo)x=-x;
    }
    inline void read1(char *s){
        char ch=getchar();
        for (;blank(ch);ch=getchar());
        for (;!blank(ch);ch=getchar())*s++=ch;
        *s=0;
    }
    inline void read1(char &c){for (c=getchar();blank(c);c=getchar());}
    //scanf->read
    inline void read2(int &x){scanf("%d",&x);}
    inline void read2(ll &x){
        #ifdef _WIN32
            scanf("%I64d",&x);
        #else
        #ifdef __linux
            scanf("%lld",&x);
        #else
            puts("error:can¡®t recognize the system!");
        #endif
        #endif
    }
    inline void read2(double &x){scanf("%lf",&x);}
    inline void read2(char *s){scanf("%s",s);}
    inline void read2(char &c){scanf(" %c",&c);}
    inline void readln2(char *s){gets(s);}
    //fwrite->write
    struct Ostream_fwrite{
        char *buf,*p1,*pend;
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
        void out(char ch){
            if (p1==pend){
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
            }
            *p1++=ch;
        }
        void print(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void println(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1); out('\n');
        }
        void print(ll x){
            static char s[25],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void println(ll x){
            static char s[25],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1); out('\n');
        }
        void print(double x,int y){
            static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
                1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
                100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
            if (x<-1e-12)out('-'),x=-x;x*=mul[y];
            ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
            ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
            if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
        }
        void println(double x,int y){print(x,y);out('\n');}
        void print(char *s){while (*s)out(*s++);}
        void println(char *s){while (*s)out(*s++);out('\n');}
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
        ~Ostream_fwrite(){flush();}
    }Ostream;
    inline void print(int x){Ostream.print(x);}
    inline void println(int x){Ostream.println(x);}
    inline void print(char x){Ostream.out(x);}
    inline void println(char x){Ostream.out(x);Ostream.out('\n');}
    inline void print(ll x){Ostream.print(x);}
    inline void println(ll x){Ostream.println(x);}
    inline void print(double x,int y){Ostream.print(x,y);}
    inline void println(double x,int y){Ostream.println(x,y);}
    inline void print(char *s){Ostream.print(s);}
    inline void println(char *s){Ostream.println(s);}
    inline void println(){Ostream.out('\n');}
    inline void flush(){Ostream.flush();}
    //puts->write
    char Out[OUT_SIZE],*o=Out;
    inline void print1(int x){
        static char buf[15];
        char *p1=buf;if (!x)*p1++='0';if (x<0)*o++='-',x=-x;
        while(x)*p1++=x%10+'0',x/=10;
        while(p1--!=buf)*o++=*p1;
    }
    inline void println1(int x){print1(x);*o++='\n';}
    inline void print1(ll x){
        static char buf[25];
        char *p1=buf;if (!x)*p1++='0';if (x<0)*o++='-',x=-x;
        while(x)*p1++=x%10+'0',x/=10;
        while(p1--!=buf)*o++=*p1;
    }
    inline void println1(ll x){print1(x);*o++='\n';}
    inline void print1(char c){*o++=c;}
    inline void println1(char c){*o++=c;*o++='\n';}
    inline void print1(char *s){while (*s)*o++=*s++;}
    inline void println1(char *s){print1(s);*o++='\n';}
    inline void println1(){*o++='\n';}
    inline void flush1(){if (o!=Out){if (*(o-1)=='\n')*--o=0;puts(Out);}}
    struct puts_write{
        ~puts_write(){flush1();}
    }_puts;
    inline void print2(int x){printf("%d",x);}
    inline void println2(int x){printf("%d\n",x);}
    inline void print2(char x){printf("%c",x);}
    inline void println2(char x){printf("%c\n",x);}
    inline void print2(ll x){
        #ifdef _WIN32
            printf("%I64d",x);
        #else
        #ifdef __linux
            printf("%lld",x);
        #else
            puts("error:can¡®t recognize the system!");
        #endif
        #endif
    }
    inline void println2(ll x){print2(x);printf("\n");}
    inline void println2(){printf("\n");}
    #undef ll
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;

const int N = 6;
const int M = 5e4 + 5;

#define LL long long
#define left LLL
#define right RRR

struct Point  {
    int x , y;
    friend bool operator < (Point xxx , Point yyy) {
        return (xxx.y == yyy.y) ? (xxx.x < yyy.x) : (xxx.y < yyy.y);
    }
    friend bool operator == (Point xxx , Point yyy) {
        return !(xxx < yyy) && !(yyy < xxx);
    }
};

int n , m , p , up[N][M] , le[N][M] , L[N][M] , R[N][M] , mx , val[N][M];

bool left[N][M] , right[N][M];

LL ans , dp[N * M][1 << N];
char pre[N * M][1 << N];
vector<Point>cur;

#define P(x , y) (Point) {x,y}
#define Sz(x) (int)x.size()

bool nextup(Point &cxt , Point &xtx) {
    if((cxt.x - xtx.x == 1 && cxt.y == xtx.y) || (cxt.y - xtx.y == 1 && cxt.x == xtx.x)) return 1;
    return 0;
}

#define iii  val[a.x][a.y]

int recov(Point xxx , int cur) {
    //¡À????D¡ä¨ª!,¨°?o¨®?¨¹2??¨®?¨ª2??¨®¡ã¨¦,¡À¨¹?a?a¨¤¨¤¡ä¨ª?¨®
    Point a = xxx;
    int v = val[xxx.x][xxx.y];
    a.x --;
    int res = 0;
    if(left[a.x][a.y] && cur) res += le[xxx.x][xxx.y]; else if(right[a.x][a.y] && !cur) res +=  le[xxx.x][xxx.y];
    a.x += 2;
    if(left[a.x][a.y] && cur) res += le[xxx.x + 1][xxx.y]; else if(right[a.x][a.y] && !cur) res += le[xxx.x + 1][xxx.y];
    a.x --;a.y --;
    if(left[a.x][a.y] && cur) res += up[xxx.x][xxx.y]; else if(right[a.x][a.y] && !cur) res +=  up[xxx.x][xxx.y];
    a.y += 2;
    if(left[a.x][a.y] && cur) res += up[xxx.x][xxx.y + 1]; else if(right[a.x][a.y] && !cur) res += up[xxx.x][xxx.y + 1];
    return res;
}

void calc(int x , vector<Point>&wh , vector<Point>&ret) {
    char s = (1 << m);
    for(int i = 0;i <= Sz(wh);++ i) {
        for(int j = 0;j < s;++ j) dp[i][j] = 1e16 , pre[i][j] = 0;
    }
    dp[0][0] = 0; LL res;
    for(int i = 1;i <= Sz(wh);++ i) {
        Point a; register char p;
         for(register char cur = 0;cur <= 1;++ cur) {
            LL ph = recov(wh[i - 1] , cur);
            if(cur == 1 && R[wh[i - 1].x][wh[i - 1].y] <= x || (cur == 0 && L[wh[i - 1].x][wh[i - 1].y] > x)) continue;
            for(register char j = 0;j < s;j ++) if(dp[i - 1][j] <= 1e10) {
                res = ph;
                for(register char k = 0;k < m;++ k) if(i >= 2 + k){
                    p = (j & (1 << k)); if(p) p = 1;
                    if(p ^ cur && nextup(wh[i - 1] , wh[i - k - 2])) {
                        if(wh[i - k - 2].y == wh[i - 1].y) res += le[wh[i - 1].x][wh[i - 1].y]; else res += up[wh[i - 1].x][wh[i - 1].y];
                    }
                }
                int nowtype = j << 1; if(nowtype & (1 << m)) nowtype -= (1 << m);
                nowtype += cur;
                if(dp[i - 1][j] + res < dp[i][nowtype]) {
                    dp[i][nowtype] = dp[i - 1][j] + res;
                    pre[i][nowtype] = j;
                }
            }
        }
    }
    LL no = -1 , Min = 1e15;
    for(int i = 0;i < s;i ++) {
        if(dp[Sz(wh)][i] < Min) {
            Min = dp[Sz(wh)][i]; no = i;
        }
    }
    int xx = Sz(wh) , yy = no;
    while(1) {
        if(!xx) break;
        if(!(yy & 1)) ret.push_back(wh[xx - 1]);
        yy = pre[xx][yy]; xx --;
    }
    reverse(ret.begin() , ret.end());
    return;
}

void solve(short l , short r , vector<Point>&wh) {
    if(l > r) return;
    if(!wh.size()) return;
    short mid = (l + r) >> 1;
    vector<Point>Left;
    calc(mid , wh , Left);
    for(int i = 0;i < (int) Left.size();++ i) {
        left[Left[i].x][Left[i].y] = 1; val[Left[i].x][Left[i].y] = mid;
    }
    vector<Point>Right; Right.clear();
    for(int i = 0;i <(int)wh.size();++ i) if(!left[wh[i].x][wh[i].y]) {
        Right.push_back(wh[i]); val[wh[i].x][wh[i].y] = mid + 1;
    }
    solve(mid + 1 , r , Right);
    for(int i = 0;i < (int) Left.size();++ i) left[Left[i].x][Left[i].y] = 0;
    for(int i = 0;i < (int) Right.size();++ i) right[Right[i].x][Right[i].y] = 1;
    solve(l , mid - 1 , Left);
}

int main(void) {
//  freopen("data.txt" , "r" , stdin);
    read(n); read(m);
    for(int i = 1;i <= m;++ i) {
        for(int j = 1;j <= n;++ j) read(L[i][j]) , read(R[i][j]) ,mx = max(mx , R[i][j]);
    }
    for(int i = 1;i <= m;++ i) for(int j = 1;j <= n - 1;j ++) read(up[i][j + 1]);
    for(int i = 1;i < m;++ i) for(int j = 1;j <= n;j ++) read(le[i + 1][j]);
    for(int i = 1;i <= m;++ i) for(int j = 1;j <= n;j ++) cur.push_back(P(i , j));
    sort(cur.begin() , cur.end());
    solve(0 , mx, cur);
    ans = 0;
    for(int i = 1;i <= m;++ i) {
        for(int j = 1;j <= n;++ j) {
            ans += abs(val[i][j] - val[i][j - 1]) * up[i][j];
            ans += abs(val[i][j] - val[i - 1][j]) * le[i][j];
        }
    }
    cout << ans << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值