• 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)时,因为没有周转的地方,所以可能没有解,所以我们需要特判一下。

  • 相关阅读:
    《乘法运算定律》
    pytest(三十九)--内置request读取项目的根目录 rootdir
    《乘除法意义及各部分关系》
    《比例尺》
    《百分数》
    《8的乘法口诀》
    《1升有多少》
    ant-design-vue 上传图片组件
    ant-design-vue快速搭建
    js实现无缝滚动
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11698762.html
Copyright © 2020-2023  润新知