2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) E,F

E

  • 题意: 一个起点,可以将火车点割掉,问最小的代价使得起点不能到达边界.
  • 思路: 拆点,火车点的入边到出边流量是割掉的价格,其他都是INF.最小割就是答案

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 45;
const int M = N*N*2;
const int INF = 0x3f3f3f3f;
int n,m,k;

struct node{
    int x,y;
};
struct E{
    int u,v,flow,nxt;
    E(){}
    E(int u,int v,int flow,int nxt):u(u),v(v),flow(flow),nxt(nxt){}
}e[M*M];
int sp,tp,tot;
int head[M],dis[M];
void init(){
    tot = 0;    memset(head,-1,sizeof head);
}
void add(int u,int v,int flow){
    e[tot] = (E){u,v,flow,head[u]};   head[u] = tot++;
    e[tot] = (E){v,u,0,head[v]};   head[v] = tot++;
}
int bfs(){
    static int q[M];
    int qtop = 0,qend = 0,u,v;
    memset(dis,-1,sizeof dis);
    dis[sp] = 0;    q[qend++] = sp;
    while(qtop != qend){
        u = q[qtop++];
        for(int i=head[u];~i;i=e[i].nxt){
            v = e[i].v;
            if(dis[v]==-1&&e[i].flow){
                dis[v] = dis[u]+1;
                q[qend++] = v;
            }
        }
    }
    return dis[tp] != -1;
}
int dfs(int u,int flow){
    int res = 0,v,d;
    if(u==tp)   return flow;
    for(int i=head[u];~i&&flow;i=e[i].nxt){
        v = e[i].v;
        if(dis[v]==dis[u]+1 && e[i].flow){
            d = dfs(v,min(e[i].flow,flow));
            e[i].flow -= d; e[i^1].flow +=d;
            res += d;   flow-=d;
        }
    }
    if(!res)    dis[u] = -2;
    return res;
}
int dinic(){
    int ans = 0;
    while(bfs()){
        ans += dfs(sp,INF);
// cerr << ans << endl;
    }
    return ans;
}
char ma[N][N];
int cost[N];
const int dir[4][2] = {{1,0},{-1,0},{0,-1},{0,1}};
int toP(int x,int y){
    return (x-1)*m+y;
}
void build(){
    int x,y,cp,np;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            cp = toP(i,j);
            for(int k=0;k<4;++k){
                x = i + dir[k][0];  y = j + dir[k][1];
                if(x<=0 || x>n || y<=0 || y>m){
                    add(cp+n*m,tp,INF); // 当前的出点到终点
                }else{
                    np = toP(x,y);
                    add(cp+n*m,np,INF); // 当前的出点到下一点的入点
                }
            }

            if(ma[i][j]=='B'){  // 起点
                add(sp,cp,INF);
            }
            if(ma[i][j]>='a' && ma[i][j]<='z'){
                add(cp,cp+n*m,cost[ma[i][j]-'a']);  // 当前点的入点到出点
            }else{
                add(cp,cp+n*m,INF);
            }
        }
    }
}

int main(){
    scanf("%d%d%d",&m,&n,&k);
    tp = n*m*2+10; sp = tp+1;
    for(int i=1;i<=n;++i){
        scanf("%s",ma[i]+1);
    }
    for(int i=0;i<k;++i){
        scanf("%d",&cost[i]);
    }
    init();
    build();
cerr << "START\n";
    int ans = dinic();
    if(ans ==INF )  ans = -1;
    printf("%d\n",ans);
    return 0;
}

F

  • 题意: 求奇数次矩形覆盖的面积
  • 思路: 扫描线,由于是奇数次覆盖,可以变成0次和1次覆盖,更新时直接将覆盖次数异或1翻转.

#include<bits/stdc++.h>
#define ll long long
#define ls(r)   r<<1
#define rs(r)   r<<1|1
using namespace std;
const int N = 1e5+10;

struct node{
    int l,r;
    int lf,rf;
    int cover;
    ll len;
}sgt[N<<3];
int y[N<<1];
struct Line{
    int x,y1,y2,state;
    bool operator < (Line oth)const{
        if(x == oth.x)  return state  > oth.state;
        return x < oth.x;
    }
}line[N<<1];
void push_up(int rt){
    sgt[rt].len = sgt[ls(rt)].len + sgt[rs(rt)].len;
}
void update(int rt){    // 翻转被覆盖的长度,原来被覆盖的取消掉,未被覆盖的添加上
    sgt[rt].len = sgt[rt].r - sgt[rt].l - sgt[rt].len;
}
void push_down(int rt){
    if(sgt[rt].cover){  // 当前区间被覆盖,更新子区间
        sgt[ls(rt)].cover ^= 1;
        sgt[rs(rt)].cover ^= 1;
        update(ls(rt));
        update(rs(rt));
        sgt[rt].cover = 0;
    }
}

void build(int l,int r,int rt){
    sgt[rt].l = y[l];   sgt[rt].r = y[r];
    sgt[rt].lf = l; sgt[rt].rf = r;
    if(r-l<=1)  return ;
    int m = (l+r)>>1;
    build(l,m,ls(rt));
    build(m,r,rs(rt));
}
void modify(int yl,int yr,int rt){
    int lf = sgt[rt].l , rf = sgt[rt].r;
    if(yl<=lf && yr>=rf){   // 完全覆盖
        update(rt);
        sgt[rt].cover ^=1;
        return ;
    }
    push_down(rt);
    if(yl<sgt[ls(rt)].r)    modify(yl,yr,ls(rt));
    if(yr>sgt[rs(rt)].l)    modify(yl,yr,rs(rt));
    push_up(rt);
}
int main(){
    int n,x1,y1,x2,y2;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        y[i] = y1;  y[i+n] = y2;
        line[i] = (Line){x1,y1,y2,1};
        line[i+n] = (Line){x2,y1,y2,-1};
    }
    sort(y+1,y+1+n*2);
    sort(line+1,line+1+n*2);
    int m = unique(y+1,y+1+n*2)-y-1;
    build(1,m,1);
    ll ans = 0;
    for(int i=1;i<=n*2;++i){
        ans += sgt[1].len * (line[i].x - line[i-1].x);
        modify(line[i].y1,line[i].y2,1);
    }
    printf("%I64d\n",ans);
}

原文地址:https://www.cnblogs.com/xxrlz/p/11622677.html

时间: 2024-08-23 20:10:49

2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) E,F的相关文章

2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Solution

A:Alphabet Solved. 签. 1 #include<bits/stdc++.h> 2 using namespace std; 3 char s[60]; 4 int f[60]; 5 int main(){ 6 scanf("%s",s+1); 7 int n=strlen(s+1); 8 for(int i=1;i<=n;i++) 9 { 10 f[i]=1; 11 } 12 for(int i=2;i<=n;i++) 13 { 14 for(

2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Solution

A:Exam Solved. 温暖的签. 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e3 + 10; 6 7 int k; 8 char str1[maxn], str2[maxn]; 9 10 int main() 11 { 12 while(~scanf("%d",&k)) 13 { 14 scanf("%s", str1 + 1); 15

2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 2) P-Fear Factoring 区间内数的所有因数的和

题意就是标题. 思路: 对于每个数 a 算出 1~a 的所有因数和sum(a),输出sum(b)-sum(a-1). 关键在于如何求出 sum. 首先发现因数∈ 1 ≤ i ≤ n ,每个因数在区间[1,n]内的出现次数(不考虑4=2*2这样因数重复出现,这种情况2只算出现一次)等于 n/i (向下取整). 然后用 t = n/(n/i) 可以找到与因数i出现次数相同的最大因数(这里可能有点难理解,例如1~100区间内21作为因数出现的数字有 21 ,42 ,63 ,84:即四次.按计算机整数相

Gym - 101615J Grid Coloring DP 2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)

题目传送门 题目大意: 给出n*m的网格,有红蓝两种颜色,每个格子都必须被染色,当一个格子被染成蓝色后,这个格子左上方的一块都必须被染成蓝色,问最后的方案数量. 思路: 按照题目条件,如果有一个格子被染成了红色,则这个格子的右下方要全部被染成红色,也就是这个给出的网格能让我们染色的,是一个左上方和右下方都是阶梯型的图形,而对于每一行来说,当一个格子被染成了蓝色,那么左边的所有格子都必须被染成蓝色,所以我们设 f[ i ][ j ] 表示第 i 行 第 j 个格子被染成蓝色的方案数量,那么这个dp

ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Krak&#243;w

ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik's RectangleProblem B: What does the fox say?Problem C: Magical GCDProblem D: SubwayProblem E: EscapeProblem F: DraughtsProblem G: History courseProblem H: C

2013-2014 ACM-ICPC Pacific Northwest Regional Contest L.Languages

题意略. 思路: 这种字符串的模拟题,应该熟练使用stringstream. 详见代码: #include<bits/stdc++.h> using namespace std; map<string,string> mp; vector<string> store; void change(string& str){ for(int i = 0;i < str.length();++i){ str[i] = tolower(str[i]); } } in

2013-2014 ACM-ICPC Pacific Northwest Regional Contest D.Delta Quadrant

题意略. 思路: 由于这是一颗无根树,我们可以贪心地来删去边. 详见代码: #include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1e4 + 5; struct edge{ int from,to,len,id; edge(int a = 0,int b = 0,int c = 0,int d = 0){ from = a,to = b,len = c,id = d; } bool

2018-2019, ICPC, Asia Yokohama Regional Contest 2018 (Gym - 102082)

2018-2019, ICPC, Asia Yokohama Regional Contest 2018 A - Digits Are Not Just Characters 签到. B - Arithmetic Progressions 题意:从给定的集合中选出最多的数构成等差数列. 题解:数字排序后,设\(dp[i][j]\)表示等差数列最后一个数字为\(a[i]\),倒数第二个数字为\(a[j]\)的最大个数.然后对于每一位枚举 \(i\),\(lower\_bound()\)找有无合法的

2018 ICPC Asia Jakarta Regional Contest

题目传送门 题号 A B C D E F G H I J K L 状态 Ο . . Ο . . . . Ο . . Ο Ο:当场 Ø:已补 .  :  待补 A. Edit Distance Thinking:kk pai爷 Code:kk 不能直接反转,比如"010101",直接反转后就变成"101010",右移一位,然后加个0就可以了. 所以要先统计01的数量,如果0大于1,就全变成1,1大于0,就全变成0(从数量上的改变就大于s/2了),相等的话,就看首位是0