给你一幅行数不超过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;
}