The 2017 ACM-ICPC Asia Beijing Regional Contest

传送门

E - Cats and Fish

模拟题意即可。

F - Secret Poems

模拟。


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head

char mtx[107][107];
char st[107*107];
    int n;
inline char rc() {
    static char c; do c=getchar(); while(c<=' ');
    return c;
}

inline void getst1() {
    int x=0,y=0;
int chn=0;
    #define U() do{x--;st[chn++]=mtx[x][y];}while(0)
    #define D() do{x++;st[chn++]=mtx[x][y];}while(0)
    #define L() do{y--;st[chn++]=mtx[x][y];}while(0)
    #define R() do{y++;st[chn++]=mtx[x][y];}while(0)
    #define RU() do{y++;x--;st[chn++]=mtx[x][y];}while(0)
    #define DL() do{x++;y--;st[chn++]=mtx[x][y];}while(0)
        st[chn++]=mtx[x][y];
        if(n%2==0) {
            REP(i,1,n) {
                if((i&1) ==1) {
                    R(); REP(j,0,i)DL();
                } else {
                    D(); REP(j,0,i)RU();
                }
            }
            PERE(i,n-2,0) {
                if((i&1)==0) {
                    R(); REP(j,0,i)RU();
                } else {
                    D(); REP(j,0,i)DL();
                }
            }
        } else {
            REP(i,1,n) {
                if((i&1)==1) {
                    R(); REP(j,0,i)DL();
                } else {
                    D(); REP(j,0,i)RU();
                }
            }
            PERE(i,n-2,0) {
                if((i&1)==1) {
                    D(); REP(j,0,i)DL();
                } else {
                    R(); REP(j,0,i)RU();
                }
            }
        }
        st[chn]=0;
        #undef U
        #undef D
        #undef L
        #undef R
        #undef RU
        #undef DL
}
inline void writest() {
    int x=0,y=0;
    int chn=0;
    #define WR() do{mtx[x][y]=st[chn++];}while(0)
    #define R() do{y++;WR();}while(0)
    #define L() do{y--;WR();}while(0)
    #define D() do{x++;WR();}while(0)
    #define U() do{x--;WR();}while(0)
    WR();
    REP(i,1,n)R();
    int k=0;
    PERE(i,n-1,0) {
        if(k==0) {
            REP(j,0,i) D();
            k++; i++;
        } else if(k==1){
            REP(j,0,i) L();
            k++;
        } else if(k==2){
            REP(j,0,i) U();
            k++; i++;
        } else if(k==3){
            REP(j,0,i) R();
            k=0;
        }
    }
}
int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(0); cout.tie(0);
    //cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(~scanf("%d", &n)) {
        REP(i,0,n)REP(j,0,n) mtx[i][j]=rc();


        getst1();
        writest();

        REP(i,0,n) {
            REP(j,0,n) {
                putchar(mtx[i][j]);
            }
            putchar('\n');
        }
    }
    return 0;
}

G - Liaoning Ship’s Voyage

BFS+判断线段相交。

Code ```cpp #include #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) #ifdef Local #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0) void err() { std::cout << '\n'; } template void err(T a, Args...args) { std::cout << a << ' '; err(args...); } #else #define dbg(...) (void)0 #endif void pt() {std::cout << '\n'; } template void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); } using namespace std; typedef long long ll; typedef pair pii; //head inline char gch() { static char x; do x=getchar(); while(x<=' '); return x; } #define EPS 1e-6 inline int dcmp(double x) { if(fabs(x) q; inline void bfs() { if(mp[0][0]=='#') { puts("-1"); return; } REP(i,0,n) REP(j,0,n) { dis[i][j]=0x3f3f3f3f3f; } dis[0][0]=0; q.push((node){0,0}); const int dx[]={0,1,1,1,0,-1,-1,-1}; const int dy[]={1,1,0,-1,-1,-1,0,1}; while(!q.empty()) { node now=q.front(); q.pop(); REP(i,0,8) { node nxt=(node){now.x+dx[i], now.y+dy[i]}; if(nxt.x =0 && nxt.y =0 && mp[nxt.x][nxt.y]=='.' && dis[nxt.x][nxt.y]>dis[now.x][now.y]+1) { Point z1=(Point){now.x,now.y}; Point z2=(Point){nxt.x,nxt.y}; bool go1=segpsec(z1,z2,sjx[0],sjx[1]); bool go2=segpsec(z1,z2,sjx[1],sjx[2]); bool go3=segpsec(z1,z2,sjx[2],sjx[0]); if(go1 || go2 || go3) continue; Point ps[3]; int pn=0; if(segsec(z1,z2,sjx[0],sjx[1])) if(dcmp(cross(z2-z1,sjx[0]-sjx[1]))!=0) {ps[pn++]=llsec(z1,z2,sjx[0],sjx[1]);} if(segsec(z1,z2,sjx[1],sjx[2])) if(dcmp(cross(z2-z1,sjx[1]-sjx[2]))!=0) {ps[pn++]=llsec(z1,z2,sjx[1],sjx[2]);} if(segsec(z1,z2,sjx[2],sjx[0])) if(dcmp(cross(z2-z1,sjx[2]-sjx[0]))!=0) {ps[pn++]=llsec(z1,z2,sjx[2],sjx[0]);} if(pn==3) continue; if(pn==2 && in2((ps[0].x+ps[1].x)/2 , (ps[0].y+ps[1].y)/2)) { continue; } dis[nxt.x][nxt.y]=dis[now.x][now.y]+1; q.push(nxt); } } } if(dis[n-1][n-1]<0x3f3f3f3f) { printf("%d\n", dis[n-1][n-1]); } else { puts("-1"); } } int main() { //ios::sync_with_stdio(false); //cin.tie(0); cout.tie(0); //cout << fixed << setprecision(20); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif while(~scanf("%d", &n)) { REP(i,0,3) scanf("%lf%lf", &sjx[i].x, &sjx[i].y); //REP(i,0,n+1) REP(j,0,n+1) mp[i][j]='.'; REP(i,0,n) REP(j,0,n) { mp[j][n-1-i]=gch(); } draw(); #ifdef Local REP(i,0,n) { REP(j,0,n) { putchar(mp[j][n-1-i]); } putchar('\n'); } #endif bfs(); } return 0; } ```

H - Puzzle Game

题意:
给出一个\(n*m\)的矩阵,每个位置有对应权值,可能为负。
现在给定一个\(p\),能替换一个位置的权值。问最后的最大子矩阵最小权值为多少。

思路:

  • 考虑枚举每个位置进行修改,然后快速维护答案;
  • 显然修改操作只会影响包含当前位置的最大子矩阵,我们还需要快速求出其余位置的最大子矩阵。
  • 那么我们预处理出\(up,down,left,right\)表示四个方向的最大子矩阵,就可以快速求出不包含当前点的答案了。这可以直接\(O(n^3)\)预处理。
  • 包含当前位置的最大子矩阵,我们可以任选一个最大子矩阵,然后在其内部枚举即可。
  • 正确性?
  • 对于与其重合的最大子矩阵,我们枚举时会考虑到交点;否则,其余的最大子矩阵,我们求出其余方向的矩阵时会考虑到。

简单说就直接考虑包含和不包含两种情况,不包含情况预处理出来,包含的情况直接考虑最大子矩阵即可。
预处理可以枚举两行、两列然后求最大子序列和。
详见代码:


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
// #define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 155;

int n, m, p;
int a[N][N];
int Up[N], Down[N], Left[N], Right[N];
int u, d, l, r;
int sum[N], res[N];

int calc() {
    int tot = -INF;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) sum[j] = 0;
        for(int j = i; j <= n; j++) {
            for(int k = 1; k <= m; k++) sum[k] += a[j][k];
            int p = 0;
            for(int k = 1; k <= m; k++) {
                res[k] = res[k - 1] + sum[k];
                if(res[k] - res[p] > tot) {
                    tot = res[k] - res[p];
                    u = i, d = j, l = p + 1, r = k;
                }
                if(res[k] < res[p]) p = k;
            }
        }
    }
    dbg(u, d, l, r, tot);
    return tot;
}

void calc1() {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) sum[j] = 0;
        for(int j = i; j <= n; j++) {
            int tot = -INF;
            for(int k = 1; k <= m; k++) sum[k] += a[j][k];
            int p = 0;
            for(int k = 1; k <= m; k++) {
                res[k] = res[k - 1] + sum[k];
                if(res[k] - res[p] > tot) {
                    tot = res[k] - res[p];
                    Down[i] = max(Down[i], tot);
                    Up[j] = max(Up[j], tot);
                }
                if(res[k] < res[p]) p = k;
            }
        }
    }
    for(int i = 2; i <= n; i++) Up[i] = max(Up[i], Up[i - 1]);
    for(int i = n - 1; i >= 1; i--) Down[i] = max(Down[i], Down[i + 1]);
}

void calc2() {
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= n; j++) sum[j] = 0;
        for(int j = i; j <= m; j++) {
            int tot = -INF;
            for(int k = 1; k <= n; k++) sum[k] += a[k][j];
            int p = 0;
            for(int k = 1; k <= n; k++) {
                res[k] = res[k - 1] + sum[k];
                if(res[k] - res[p] > tot) {
                    tot = res[k] - res[p];
                    Left[j] = max(Left[j], tot);
                    Right[i] = max(Right[i], tot);
                }
                if(res[k] < res[p]) p = k;
            }
        }
    }
    for(int i = 2; i <= m; i++) Left[i] = max(Left[i], Left[i - 1]);
    for(int i = m - 1; i >= 1; i--) Right[i] = max(Right[i], Right[i + 1]);
}

void run() {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cin >> a[i][j];
        }
    }
    for(int i = 0; i <= n + 1; i++) Up[i] = Down[i] = -INF;
    for(int i = 0; i <= m + 1; i++) Left[i] = Right[i] = -INF;
    int Max = calc();
    calc1();
    calc2();
    dbg(Up[1], Right[3], Down[2], Left[2]);
    int ans = Max;
    for(int i = u; i <= d; i++) {
        for(int j = l; j <= r; j++) {
            if(a[i][j] <= p) continue;
            ans = min(ans, max(Max - a[i][j] + p, max(Up[i - 1], 
                max(Down[i + 1], max(Left[j - 1], Right[j + 1])))));
        }
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> m >> p) run();
    return 0;
}

J - Pangu and Stones

题意:
给出\(n\)堆石子,每堆石子有\(a_i\)个。现在每次可以选择\(l\)~\(r\)堆的石子进行合并,问最后合并为一堆石子的最小代价为多少;不能合并为一堆则输出\(-1\)

思路:

扫描二维码关注公众号,回复: 7546554 查看本文章
  • 定义\(dp(l,r,k)\)表示考虑将区间\([l,r]\)分为\(k\)堆的最小代价。
  • 如果我们已经确定了一种划分方式,那么直接合并起来,代价为\(sum_r-sum_{l-1}\)
  • 假设现在\(k=1\),显然我们要将\([l,r]\)个数的堆合并为一堆,注意到对于所有的\(x\)堆合并为一堆,我们可以将其划分为\(x-1\)堆和\(1\)堆的合并;
  • \(k>1\),此时不考虑合并,考虑通过一种最小的代价将其划分为\(k\)堆,同样地,我们通过枚举中间点,然后将序列划分为\(k-1\)\(1\)堆,这能覆盖到所有的情况。

所以\(dp\)的状态转移方程为:
\[ \left\{ \begin{aligned} &dp[i][j][1]=min\{dp[i][k][x-1]+dp[k+1][j][1]+sum_{j}-sum_{i-1}\}\\ &dp[i][j][x]=min\{dp[i][k][x-1]+dp[k+1][j][1],x>1\} \end{aligned} \right. \]
详见代码:(感觉说不清楚QAQ)


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
// #define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 105;

int n, l, r;
int a[N], sum[N];
int dp[N][N][N];

void run() {
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        sum[i] = sum[i - 1] + a[i];
    }
    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= n; j++) 
            for(int k = 0; k <= n; k++) 
                dp[i][j][k] = INF;  
    for(int i = 1; i <= n; i++) {
        dp[i][i][1] = 0;
    }
    for(int len = 2; len <= n; len++) {
        for(int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
            for(int k = i; k < j; k++) {
                for(int t = l - 1; t <= r - 1; t++) {
                    if(k - i + 1 >= t)
                        dp[i][j][1] = min(dp[i][j][1], dp[i][k][t] + dp[k + 1][j][1] + sum[j] - sum[i - 1]);
                }
            }
            for(int t = 2; t <= j - i + 1; t++) {
                for(int k = i; k < j; k++) {
                    if(k - i + 1 >= t - 1)
                    dp[i][j][t] = min(dp[i][j][t], dp[i][k][t - 1] + dp[k + 1][j][1]);
                }
            }
        }
    }
    if(dp[1][n][1] == INF) dp[1][n][1] = 0;
    pt(dp[1][n][1]);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> l >> r) run();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/heyuhhh/p/11723461.html