Codeforces Round #355 (Div. 2)

link

D Vanya and Treasure

題意:

n*m的格子,一開始再(1,1)的位置,每個位置都有一個寶箱,每個寶箱都有一個編號,編號爲x的寶箱可以被編號爲x-1的寶箱裏的鑰匙打開,1號寶箱沒有鎖,問打開p號寶箱最少走多少步

思路:

很顯然, 由於 x 只能打開 x+1 的, 所以我們很容易的就想到了暴力 dp, 但是如果 x 的個數, x + 1 的個數乘起來很大的話, 那麼我們就會很浪費時間, 所以結果就是

  • 乘積 小於 n*m 那麼我們就直接暴力求結果,
  • 乘積大於 n*m, 那麼我們就跑一遍 bfs, 一開始把所有 x 寶箱的位置加入到隊列, 然後跑完bfs 之後,我們只更新 x + 1 的答案。

反思:

我一開始只想到了暴力 dp 的方法, 結果顯而易見的就 T 了, 一時半會兒也想不到解決的辦法,
然後纔去看別人的博客,看到了小數據暴力, 大數據bfs 的方法,

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+1000;
const int M = 400;
const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}

typedef pair<int,int> P;
vector<P>f[N];
int n,m,p,x,k;
bool vis[M][M];
int dis[M][M],ans[M][M],Ans;
void solve1(int now){
	if (now == 0) ans[1][1] = 0;
	for (auto itx:f[now]){
		for (auto ity: f[now+1]){
			ans[ity.first][ity.second] = min(ans[ity.first][ity.second], ans[itx.first][itx.second] + abs(ity.first - itx.first) + abs(itx.second - ity.second));
		}
	}
	for (auto it: f[now+1]){
		if (now + 1 == p) Ans = min(Ans, ans[it.first][it.second]);
	}
	if (now == 0 && k != 1) ans[1][1] = ans[0][0];
}
queue<P>q;
void solve2(int now){
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			dis[i][j] = ans[0][0],vis[i][j] = 0;

	if (now == 0) dis[1][1] = 0;
	else {
		for (auto it: f[now])
			dis[it.first][it.second] = ans[it.first][it.second];
	}		
	while(!q.empty()) q.pop();
	for (auto it: f[now]){
		q.push(P{it.first, it.second});
		vis[it.first][it.second] = 1;
	}
	while(!q.empty()){
		P u = q.front(); q.pop();
		for (int i = 0; i < 4; ++i){
			int x = u.first + dx[i], y = u.second + dy[i];
			if (x > 0 && x <= n && y > 0 && y <= m){
				if (dis[x][y] > dis[u.first][u.second] + 1){
					dis[x][y] = dis[u.first][u.second] + 1;
					if (vis[x][y] == 0){
						q.push(P{x,y});
						vis[x][y] = 1;
					}
				}
			}
		}
		vis[u.first][u.second] = 0;
	}
	for (auto it: f[now+1]){
		ans[it.first][it.second] = dis[it.first][it.second];
	}	
}
int main(){
	memset(ans, 0x3f3f, sizeof ans);
	Ans = ans[0][0];
	scanf("%d%d%d",&n,&m,&p);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j){
			scanf("%d",&x);
			f[x].push_back(P{i,j});
			if (i == j && i == 1) k = x;
		}
	f[0].push_back(P{1,1});
	ans[1][1] = 0;
	for (int i = 0; i < p; ++i){
		if ((int)f[i].size() * (int)f[i+1].size() <= n*m) solve1(i); else solve2(i);	
		// logs(i);
	}	
	printf("%d\n",Ans);
	return 0;
}

E. Vanya and Balloons

題意:

n*n的格子,每個格子都有一個數,現在可以在一個格子上放炸彈,炸彈炸+ x 形狀,得到的價值就是形狀裏面的值的乘積,問乘積最大是多少。炸彈炸了之後, 四個方向的長度要是一樣的。

思路:

問乘積最大, 由此可見, 乘積的路上不可以有 0,如果有 0 , 那就前功盡棄。
還有一個問題,如果乘起來的話, 最終的結果一定會很大, 所以對每一個數 取 log, log 之後乘就變成了加,
所以我們就找加最大的就好了,

取了log 之後, 我們要統計八個方向的前綴和, 還有 0 的位置, 最後就是 n*n 的掃描一遍, 找一個加起來最大的就好了,
八個方向,分成兩組, + 要四個方向, x 也是四個方向。
至於怎麼找, 對於每個位置,我要找 四個方向上0最近的長度,根據這個長度,計算出來加和, 找加和最大的,標記一下, 最後答案重新乘起來就好了,

反思:

通過了這個題,可以把 乘法變加法。 這是一個小技巧。

#include<bits/stdc++.h>
using namespace std;
const int N = 1009;
const int mod = 1e9 + 7;
const int dx[8] = {0,-1,-1,-1,0,1,1,1};
const int dy[8] = {-1,-1,0,1,1,1,0,-1};
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,m;
double a[N][N],f[N][N][3][3];
int b[N][N];
int g[N][N][3][3];
void solve(){
    int x,y;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j){
            for (int k = 0; k < 3; ++k){
                x = i + dx[k]; y = j + dy[k];
                if (a[i][j] != -1) {
                    f[i][j][dx[k]][dy[k]] = f[x][y][dx[k]][dy[k]] + a[i][j];
                    g[i][j][dx[k]][dy[k]] = g[x][y][dx[k]][dy[k]] + 1;
                } else {
                    f[i][j][dx[k]][dy[k]] = 0;
                    g[i][j][dx[k]][dy[k]] = 0;
                }
            }
        } 

    for (int i = 1; i <= n; ++i)
        for (int j = n; j > 0; --j){
            for (int k = 3; k < 4; ++k){
                x = i + dx[k]; y = j + dy[k];
                if (a[i][j] != -1) {
                    f[i][j][dx[k]][dy[k]] = f[x][y][dx[k]][dy[k]] + a[i][j];
                    g[i][j][dx[k]][dy[k]] = g[x][y][dx[k]][dy[k]] + 1;
                } else {
                    f[i][j][dx[k]][dy[k]] = 0;
                    g[i][j][dx[k]][dy[k]] = 0;
                }
            }
        } 
    for (int i = n; i > 0; --i)
        for (int j = n; j > 0; --j){
            for (int k = 4; k < 7; ++k){
                x = i + dx[k]; y = j + dy[k];
                if (a[i][j] != -1) {
                    f[i][j][dx[k]][dy[k]] = f[x][y][dx[k]][dy[k]] + a[i][j];
                    g[i][j][dx[k]][dy[k]] = g[x][y][dx[k]][dy[k]] + 1;
                } else {
                    f[i][j][dx[k]][dy[k]] = 0;
                    g[i][j][dx[k]][dy[k]] = 0;
                }
            }
        } 
    for (int i = n; i > 0; --i)
        for (int j = 1; j <= n; ++j){
            for (int k = 7; k < 8; ++k){
                x = i + dx[k]; y = j + dy[k];
                if (a[i][j]!=-1) {
                    f[i][j][dx[k]][dy[k]] = f[x][y][dx[k]][dy[k]] + a[i][j];
                    g[i][j][dx[k]][dy[k]] = g[x][y][dx[k]][dy[k]] + 1;
                } else {
                    f[i][j][dx[k]][dy[k]] = 0;
                    g[i][j][dx[k]][dy[k]] = 0;
                }
            }
        } 
}
void solve1(){
    double ans = -1,tim;
    int I = 1,J = 1,K = -1,T,tmp;
    for (int i = 1; i <= n; ++i){
        for (int j = 1; j <= n; ++j){
            if (a[i][j] == -1) continue;
            tmp = n;
            tim = 0;
            for (int k = 0;  k < 8; k+=2)
                tmp = min(tmp, g[i][j][dx[k]][dy[k]]);
            for (int k = 0; k < 8; k += 2)
                tim += f[i][j][dx[k]][dy[k]] - f[i+dx[k]*tmp][j+dy[k]*tmp][dx[k]][dy[k]];
            tim -= 3*a[i][j];
            if (tim > ans) {
                ans = tim;
                I = i, J = j, K = 0; T = tmp;
            }
            tmp = n;
            tim = 0;
            for (int k = 1;  k < 8; k+=2)
                tmp = min(tmp, g[i][j][dx[k]][dy[k]]);
            for (int k = 1; k < 8; k += 2)
                tim += f[i][j][dx[k]][dy[k]] - f[i+dx[k]*tmp][j+dy[k]*tmp][dx[k]][dy[k]];
            tim -= 3*a[i][j];
            if (tim > ans) {
                ans = tim;
                I = i, J = j, K = 1; T = tmp;
                // logs(i,j,ans,tmp);
            }     
            // logs(i,j,tmp);
        }
    }
    long long Ans; 
    if (K == -1){
        puts("0");
    } else{
        Ans = b[I][J];
        for (int i = 1; i < T; ++i){
            for (int j = K; j < 8; j+=2)
                Ans = (Ans * b[I+dx[j]*i][J+dy[j]*i]) % mod;
        }
        printf("%lld\n",Ans);
    }
    
}
int main(){
    int x;
    scanf("%d",&n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j){
            scanf("%1d",&x);
            if (x) a[i][j] = log2(x); else a[i][j] = -1;
            b[i][j] = x;
            // logs(a[i][j],b[i][j]);
        }
    solve();
    solve1();
    return 0;
}
發佈了237 篇原創文章 · 獲贊 13 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章