zoukankan      html  css  js  c++  java
  • Codeforces Round #593 (Div. 2)

    传送门

    A. Stones

    签到。

    B. Alice and the List of Presents

    单独考虑每个数的贡献即可。
    答案为((2^{m}-1)^n)

    C. Labs

    构造就类似于:
    1 6 7
    2 5 8
    3 4 9
    这样就行了。
    证明我也不会,但感觉这样能使得每一行都较为均衡。

    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 Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 305;
     
    int n;
    int mp[N][N];
     
    void run() {
    	cin >> n;
    	for(int j = 1; j <= n; j++) {
    		int st = (j - 1) * n + 1;
    		if(j & 1) {
    			for(int i = n; i >= 1; i--, st++) {
    				mp[i][j] = st;
    			}
    		} else {
    			for(int i = 1; i <= n; i++, st++) {
    				mp[i][j] = st;
    			}			
    		}
    	}
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= n; j++) {
    			cout << mp[i][j] << " 
    "[j == 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) run();
        return 0;
    }
    

    D. Alice and the Doll

    题意:
    给出一个(ncdot m,n,mleq 10^5)大小的网格图,上面有些位置可能有障碍。
    现在要求,每个格子只能经过一次,并且在每个格子有两个选择:直走或者右转。初始位于((1,1))位置,方向为向右。
    问能否走遍所有非障碍的点。

    思路:
    把题读成一个位置可以经过多次,但只能右转一次,想了一小时假题
    因为只能经过一次,那么我们路线肯定是“回路”型的,并且肯定是贪心地走。
    那么我们每行每列存障碍,然后模拟这个过程就行。
    代码中用了一个矩形表示当前范围。注意每次删障碍时肯定要删除一个矩形,矩形内如果有空地那就不合法,因为不可能再走过去了。
    注意矩形范围的更新。
    细节见代码:

    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 Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 1e5 + 5;
     
    int n, m, k;
    set <int> col[N], row[N];
     
    bool del(int up, int down, int left, int right) {
    	for(int i = up; i <= down; i++) {
    		for(int j = left; j <= right; j++) {
    			if(row[i].find(j) == row[i].end()) return false;
    			row[i].erase(j);
    			col[j].erase(i);
    			--k;
    		}
    	}
    	return true;
    }
     
    void run() {
    	for(int i = 1; i <= k; i++) {
    		int x, y; cin >> x >> y;
    		col[y].insert(x);
    		row[x].insert(y);
    	}
    	int dir = 0;
    	int up = 1, down = n, left = 1, right = m;
    	int D = 0;
    	int x = 1, y = 1;
    	while(k) {
    		if(dir == 0) {
    			auto it = row[x].begin();
    			if(it == row[x].end()) {
    				y = right;
    			} else {
    				int p = *it;
    				if(!del(up, down, p, right)) {
    					cout << "No";
    					return;
    				}
    				right = y = p - 1;
    			}
    			left += D;
    		} else if(dir == 1) {
    			auto it = col[y].begin();
    			if(it == col[y].end()) {
    				x = down;
    			} else {
    				int p = *it;
    				if(!del(p, down, left, right)) {
    					cout << "No";
    					return;
    				}
    				down = x = p - 1;
    			}
    			up += D;
    		} else if(dir == 2) {
    			auto it = row[x].rbegin();
    			if(it == row[x].rend()) {
    				y = left;
    			} else {
    				int p = *it;
    				if(!del(up, down, left, p)) {
    					cout << "No";
    					return;
    				}
    				left = y = p + 1;
    			}
    			right -= D;
    		} else {
    			auto it = col[y].rbegin();
    			if(it == col[y].rend()) {
    				x = up;
    			} else {
    				int p = *it;
    				if(!del(up, p, left, right)) {
    					cout << "No" << '
    ';
    					return;
    				}
    				up = x = p + 1;
    			}
    			down -= D;
    		}
    		dir = (dir + 1) % 4;
    		D = 1;
    		// cout << up << ' ' << down << ' ' << left << ' ' << right << '
    ';
    	}
    	cout << "Yes" << '
    ';
    }
     
    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 >> k) run();
        return 0;
    }
    

    E. Alice and the Unfair Game

    题意:
    现有(n)个方格排成一列,同时给出一个序列(a)(a_i)表示第(i)次时敲打(a_i)这个方格。
    现有个玩偶在这个方格上面走,每次敲打后可以向相邻方格走一步或者留在原地。并规定一开始可以移动一步。
    问存在多少对((x,y)),表示玩偶一开始在(x),最后在(y)位置,并且中间不会被敲打。

    思路:
    有一个观察:

    • 对于一个点(x),若其最远向右能走到(y),那么最终走到(x)~(y)之间的方格都为合法答案。
    • 向左延申同理。
    感性证明 证明的话可以感性理解一下,因为在一个时间点只能敲打一次,倒过来考虑,因为最后能够停留在$y$,假设我们是从$y-1$走过来,那么必然最后一次不会敲打$y-1$这个位置,那直接停在这个位置即可;如果我们一直卡在$y$,那也是可以往前走的。

     
    所以现在问题的关键就是对于每个位置,如何快速找到向左、向右延申的最远位置。

    因为这个题跟时间有很大关系,所以我们考虑用二维坐标((x,y))表示在(x)时刻位于第(y)个方格。那么敲打点就相当于二维平面上的一个障碍。
    问题就变为:我们从((0,y))出发,每次可以向上、向右、向下走一步,不能经过障碍,能走到的最上/最下的位置是多少。

    以最大举例:我们采用贪心的策略,用vector存储同一斜率上的所有障碍点,然后二分找到障碍点位置((x_i,y_i)),那我们只能走到((x_i,y_i-1));之后快速找到下一个(y_j ot ={y_i})的时间点(预处理下一个位置),走过去即可。

    详细细节见代码:

    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 Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 2e5 + 5, base = 1e5;
     
    int n, m;
    int a[N], nxt[N];
    vector<int> v1[N], v2[N];
    int Max[N], Min[N];
     
    void run() {
    	for(int i = 1; i < N; i++) v1[i].clear(), v2[i].clear();
    	for(int i = 1; i <= m; i++) {
    		int x; cin >> x;
    		v1[i - x + base].push_back(i);
    		v2[i + x].push_back(i);
    		a[i] = x;
    	}
    	if(n == 1 && *max_element(a + 1, a + m + 1) == 1) {
    		cout << 0 << '
    ';
    		return;
    	}
    	nxt[m] = m + 1;
    	for(int i = m - 1; i >= 1; i--) {
    		if(a[i] == a[i + 1]) nxt[i] = nxt[i + 1];
    		else nxt[i] = i + 1;
    	}
    	for(int i = 1; i <= n; i++) {
    		int x = 0, y = i;
    		while(1) {
    			int k = x - y + base;
    			auto it = lower_bound(v1[k].begin(), v1[k].end(), x + 1);
    			if(it == v1[k].end()) {
    				y += m + 1 - x;
    				break;
    			}
    			int p = it - v1[k].begin();
    			p = v1[k][p];
    			x = nxt[p] - 1, y = a[p] - 1;
    		}
    		Max[i] = min(y, n);
    	}
    	for(int i = 1; i <= n; i++) {
    		int x = 0, y = i;
    		while(1) {
    			int k = x + y;
    			auto it = lower_bound(v2[k].begin(), v2[k].end(), x + 1);
    			if(it == v2[k].end()) {
    				y -= m + 1 - x;
    				break;
    			}
    			int p = it - v2[k].begin();
    			p = v2[k][p];
    			x = nxt[p] - 1, y = a[p] + 1;
    		}
    		Min[i] = max(1, y);
    	}
    	ll ans = 0;
    	for(int i = 1; i <= n; i++) {
    		ans += (Max[i] - Min[i] + 1);
    	}
    	cout << ans << '
    ';
    }
     
    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) run();
        return 0;
    }
    

    注意一下,当(n>1)时,每个位置肯定至少存在一个解。但是当(n=1)时,因为没有周转的地方,所以可能没有解,所以我们需要特判一下。

  • 相关阅读:
    Good Bye 2014 B. New Year Permutation(floyd )
    hdu 5147 Sequence II (树状数组 求逆序数)
    POJ 1696 Space Ant (极角排序)
    POJ 2398 Toy Storage (叉积判断点和线段的关系)
    hdu 2897 邂逅明下 (简单巴什博弈)
    poj 1410 Intersection (判断线段与矩形相交 判线段相交)
    HDU 3400 Line belt (三分嵌套)
    Codeforces Round #279 (Div. 2) C. Hacking Cypher (大数取余)
    Codeforces Round #179 (Div. 2) B. Yaroslav and Two Strings (容斥原理)
    hdu 1576 A/B (求逆元)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11698762.html
Copyright © 2011-2022 走看看