Loading

Codeforces Round 736

A

1549A - Gregor and Cryptography

题目大意:
给定一个 \(P\) , \(P\) 是素数,任意找出两个基数 \(a, b\) 使得 \(P~~mod~~a = P~~mod~~b\)
\(5\leq P\leq 10^9\) \(2\leq a,b\leq P\)

solution

无脑输出 \(2\)\(P - 1\) 就好了

比赛时没看见 \(P\)​ 是素数 = =

B

1549B - Gregor and the Pawn Game

题目大意:
给出一个 \(n \times n\)​ 的棋盘,我方的所有旗子都在第 \(n\)​ 行,敌方的所有棋子都在第一行,问我方有多少棋子能走到第一行。
我方棋子行走的规则:

  • 向正前方走,当且仅当正前方没有敌方棋子的时候 \((i, j) > (i - 1, j)\)

  • 向对角线方向走,当且仅当对角线方向有敌方棋子的时候 \((i, j) > (i - 1, j - 1),(i, j) > (i - 1, j + 1)\)

solution

写的贪心水过去了 = =
贪心:先往正前方放,再放左边,最后放右边
复杂度:\(O(n)\)

code

/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define rg register
using namespace std;
const int N = 2e5 + 7;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int T, n, vis[N], ans;
char s[N], s2[N];
signed main(){
   T = read();
   while(T--) {
   	 n = read();
   	 scanf("%s", s + 1), scanf("%s", s2 + 1);
   	 memset(vis, 0, sizeof vis); ans = 0;
   	 for (int i = 1; i <= n; i++) {
   	 	if (s2[i] == '1'){	
   	 	   if (s[i] == '0') ans++;
   	 	   else if(s[i - 1] == '1' && !vis[i - 1]) ans++, vis[i - 1] = 1;
   	 	   else if(s[i + 1] == '1') ans++, vis[i + 1] = 1;
		}
	  }
	  printf("%d\n", ans);
   }
   puts("");
   return 0;
}


solution 2

二分图最大匹配:
一个棋子有可能到达的终点只有三个,然后让每个棋子向能到达的终点连边,然后跑一个最大匹配就好了
复杂度:\(O(n\sqrt n)\)

C

1549C - Web of Lies

题目大意:有 \(n\) 个有权值的点和 \(m\)条边,现在加边,删点和查询 \(q\) 次操作
加边:保证两个点之间本来没有边
删点:每次删的点满足:
1.它连的点的权值都比它大。
2.至少有一个点和它相连。
3.查询:输出没有被删除的点有哪些
\(q, n,m \leq 2\times 10^5\)

solution

结论:如果一个点连向一个比权值更大的点,这个点一定会被删,保留下的点所连向的点的权值一定都比它小。
证明: 如果一个点 \(u\) 连向了一个比它大的点 \(v\)\(u\) 想要保留下来,一定要连向一个权值比它小的点 \(w\),同理,\(w\) 想要保留下来也要连向一个比它小的点,这样一直连到最后一定会连向最小的点,最小的点就没有点可以连了,推出矛盾。

code

/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define ll long long
#define rg register
using namespace std;
const int N = 3e5 + 7;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int n, m, fag[N], Ans;
int main() {
    n = read(),m = read();
    for (int i = 1; i <= m; i++) {
        int u = read(), v = read();
        if (u > v) swap(u, v);
        if (!fag[u]) Ans++;
        fag[u]++;
    }
    int T = read();
    while(T--) {
        int opt = read();
        if (opt == 1) {
            int u = read(), v = read();
            if (u > v) swap(u, v);
            if (!fag[u]) Ans++;
            fag[u]++;
        }
        if(opt == 2) {
            int v = read(), u = read();
            if (u > v) swap(u, v);
            fag[u]--;
            if(!fag[u]) Ans--;
        }
        if(opt == 3) printf("%d\n", n - Ans);
    }
    return 0;
}

D

1549D - Integers Have Friends

题目大意

给出一个长为 \(n\)​ 的序列 \(a\)​ ,找出一个的子序列,并且存在 \(m\)​ 使得序列中所有数 \(mod~m\)​ 都相等,最大化这个子序列。

\(1\leq n \leq 2\times10^5, 1 \leq a_i\leq10^{18}\)

solution

题目关键就是构造一个大小为 \(n - 1\) 的差分数组 \(D\),其中 \(D_i = abs(A_{i + 1}- A_i)\)

如果给出一个子序列是合法的,那么任意两个元素差值的差一定 \(m\) 的倍数,因为 \(A\) 的每个元素不同,所以可以忽略 \(D_i = 0\) 的情况。

现在就可以转化为 \(GCD\) 问题,如果 \([A_i,A_j]\) 是一个合法子序列,当且仅当 \(GCD(D_i...D_{j - 1}) > 1\) ,并且 \(m\) 就是这个 \(GCD\)

区间 \(GCD\) 用线段树或者 \(RMQ\) 实现。

时间复杂度:\(O(nlogn\times log10^{18})\)

code

/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define rg register
#define int long long
using namespace std;
const int MAXN = 2e5 + 5; 
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int a[MAXN], d[MAXN], T, n, f[MAXN][40];
int gcd(int x, int y) {
   if (!y) return x;
   return gcd(y, x % y);
}
int query(int l, int r) {
   int k = (int)log2(double(r - l + 1));
   return gcd(f[l][k], f[r - (1 << k) + 1][k]);
}
signed main(){
   T = read();
   while(T--) {
   	  n = read();
   	  for (int i = 1; i <= n; i++) a[i] = read();		 	
	  for (int i = 1; i < n; i++) d[i] = abs(a[i + 1] - a[i]);
	  for (int i = 1; i < n; i++) f[i][0] = d[i];
	  for (int j = 1; (1 << j) <= n; j++) 
	    for (int i = 1; i + (1 << j) - 1 <= n; i++) 
	       f[i][j] = gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
	  int sur = 1, ans = 1;
	  for (int i = 1; i < n; i++) {
	  	  while(sur <= i && query(sur, i) == 1) sur++;
	  	  ans = max(ans, i - sur + 2);
	  }
	  printf("%lld\n", ans);
   }
   puts("");
   return 0;
}

posted @ 2021-08-02 22:41  Dita  阅读(45)  评论(0编辑  收藏  举报