2021/04/11我校ACM周赛

好难啊呜呜呜....

  • A.CF1144A Diversity Strings多样字符串
  • B.CF1144B Parity Alternated Deletions 奇偶交替删除
  • C Two Shuffled Sequences 两个乱序串
  • D. Equalize Them All 制衡
  • E. Graph Without Long Directed Paths 不带长边的有向图
  • F. The Number of Pairs
  • G. Painting Fence


A.CF1144A Diversity Strings多样字符串

VIEW
题意:我们称「多样字符串」,当且仅当一个字符串所包含的字符在字母表中毗邻,且不包含重复的字符。

  • 考场上读错了意思(考的时候看到题目是「不同的字符们」,被先入为主了吧hhh),以为要在原串的序列中出现「毗邻」,然后心态爆炸
#include 
#include 
#include 
using namespace std;
int main() {
     
    int n; cin >> n;
    string a;
    while (n --) {
     
        cin >> a;
        sort(a.begin(), a.end());
        for (string::iterator i = a.begin(); i != a.end() - 1; ++i ) {
     
            if (*(i + 1) - *(i) != 1) {
     
                cout << "No\n";
                goto Next;
            }
        }
        cout << "Yes\n";
        Next : {
      }
    }
    return 0;
}
  • 考场上用了许久理解了意思,最早想着是序列,居然想着用桶(现在看来好傻)
import collections
import string
al = string.ascii_lowercase
 
n = int(input())
 
while n != 0:
    s = input().strip()
    cnt = collections.Counter(s)
    flag1, flag2 = True, True
    m, M = 27, -1
    for i in range (0, 26):
        if cnt[al[i]] > 1:
            flag1 = False
        if cnt[al[i]] == 1:
            m = min(m, i)
            M = max(M, i)
    for i in range(m, M):
        flag2 &= cnt[al[i]]
    print("Yes" if flag1 == True and flag2 == True else "No")
    n = n - 1

B.CF1144B Parity Alternated Deletions 奇偶交替删除

VIEW
题意:给定一个数组(包含 n n n个元素),按照奇偶性交替删除元素,问执行此操作后数组最终元素之和最小为多少。例如:对于[1,1,2,3,4,5,6,7],按照[7->6->5->4->3->2->1]删除,最终返回答案1

  • 降序地删除元素,特殊的,对于奇偶交替的序列(奇偶数目之差 ≤ 1 \le1 1)一定会返回 0 0 0
#include 
#include 
#include 
using namespace std;
int main() {
     
	int n; cin >> n;
	int t;
	vector<int> odd, even;
	while (n --) {
     
	    cin >> t;
	    if (t & 1) odd.push_back(t);
	    else even.push_back(t);
	}
	int delta = odd.size() - even.size();
	if (abs(delta) <= 1) {
     
	    cout << 0 << endl;
	} else {
     
	    sort(odd.begin(), odd.end());
	    sort(even.begin(), even.end());
	    int ans = 0;
	    if (delta > 0) {
     
	        for (int i = 0; i < delta - 1; ++i) 
	            ans += odd[i];
	    } else {
     
	        delta = - delta;
	        for (int i = 0; i < delta - 1; ++i)
	            ans += even[i];
	    }
	    cout << ans << endl;
	}
	return 0;
}	

C Two Shuffled Sequences 两个乱序串

VIEW
题意:给定的数组中可能有两个子序列分别升序、降序。如果有输出之。

  • 开个桶,分别计数即可
// #include 
#include 
#include 
using namespace std;
static constexpr int N = 2e5 + 10;

int bus[N], a[N], b[N];
int main() {
     
    int n, q;
    scanf("%d", &n);
    bool flag = true;
    for (int i = 0; i < n; ++i) {
     
        scanf("%d", &q);
        bus[q] ++;
        if (bus[q] > 2) {
     
            flag = false;
            printf("NO\n");
            return 0;
        }
    }
    
    int sizea = 0, sizeb = 0;
    for (int i = 0; i < int(2e5 + 10); ++i) {
     
        if (bus[i]) {
     
            a[++sizea] = i;
            if (bus[i] == 2) {
     
                b[++sizeb] = i;
            }
        }
    }

#ifndef ONLINE_JUDGE  // 一大坨调试 
    printf("bus is \n");
    for (int i = 0;i < int(2e5 + 10); ++i) {
     
        if (!bus[i]) {
     
            continue;
        }
        printf("i : %d \t bus[i] : %d \n", i, bus[i]);
    }
    putchar(10);
  
    printf("a is \n");
    for (int i = 1;i < sizea + 1; ++i) 
        printf("%d ", a[i]);
    putchar(10);

    printf("b is \n");
    for (int i = 1;i < sizeb + 1; ++i) 
        printf("%d ", b[i]);
    putchar(10);
#endif
    printf("YES\n");
    if (flag) {
     
        printf("%d\n", sizea);
        int i = 0;
        for (int i =1; i < sizea + 1; ++i) printf("%d ", a[i]);
        putchar(10);
        printf("%d\n", sizeb);
        i = 0;
        for (int i = sizeb; i >= 1; --i) printf("%d ", b[i]);
    }
    return 0;
}

D. Equalize Them All 制衡

VIEW
题意:你可选择两个相邻元素将它们置为同一数值,求最少的操作次数。若存在非 0 0 0操作次数,输出之。

  • 分析:要先找到出现次数最多的数,这是由于我们总能将与之毗邻的数字置为这个数,同时次数依然保持最大,不会影响到最终的结果(贪心)。之后便利一次进行修改即可,遇到不同的,我们总是尝试修改为most.value,这样我们总能将most.value之间的数字修改为most.value。最后再扫一遍,保证修改完全。

要理解这里的「修改完全」,看下面我举的几个极端的例子

  • 没有区间(most.cnt == 1),顺序的遍历总能无法修改:

12
1 2 3 4 5 6 7 8 9 10 11 12

  • 无有效区间(most中间没有数字)

5
1 3 4 2 2

  • 区间没有包含全部的数(most没有完全包含全部数字)

5
1 2 3 4 2

  • 总之,为了保证修改完全,再倒序遍历一次即可

被卡了好多天呜呜呜…CE…WA…RE最后终于过了…哭哭

#include 
using namespace std;
const int N = 200097; // 注意数组大小 总之至少 2e5(n 的范围)
int arr[N];
unordered_map<int, int> has;
int main() {
     
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
     
        cin >> arr[i];
        has[arr[i]] ++; 
        // 开桶会更好...听说CF哈希表容易被卡
        // 或者你用 pb_ds STL 也可hhh
    }
    pair<int, int> most = make_pair(INT_MIN, -1);
    for (auto&v : has) {
     
        if (v.second > most.second) {
     
            most = v;
        }
    }
    int ans = n - most.second;
    cout << ans << endl;
    if (ans) {
     
        int M = most.first;
        for (int i = 2; i <= n; ++i) {
     
            if (M != arr[i - 1] || arr[i] == arr[i - 1]) continue;
            printf("%d %d %d\n", (arr[i] < arr[i - 1]) ? 1 : 2, i, i - 1);
            arr[i] = arr[i - 1];
        }
        
        for (int i = n - 1; i >= 1; --i) {
     
            if (M != arr[i + 1] || arr[i] == arr[i + 1]) continue;
            // printf("cur : \n"); 
            // 这个comment让我慢慢地找到了所有的特例hhh(哭哭)
            printf("%d %d %d\n", (arr[i] < arr[i + 1]) ? 1 : 2, i, i + 1);
            arr[i] = arr[i + 1];
        }
    }    
    return 0;
}

E. Graph Without Long Directed Paths 不带长边的有向图

VIEW
题意:能否有一种方案对给定无向图标注方向,使得图中只包含长度 ≤ 2 \le 2 2的路径?答案返回形式首先包含是否可行(Yes/No),如果可行输出一个字符串,按照给定原有无向图的顺序进行标号。例如 a → b a\rightarrow b ab,你需要输出 1 1 1,反之( b → a b\rightarrow a ba)则为 0 0 0.

  • 分析:距离不超过 2 2 2的话,首先考虑如下的一个 3 3 3环,无解
    2021/04/11我校ACM周赛_第1张图片
  • 对于这种情况,没有解使得它满足题意。事实上,对于更多的奇数环情况我们也可以断言无解

可以使用鸽巢原理证明:设奇数环的点数为 n n n,这同时也是边数。假设有解,则必有 O → O ← O O\rightarrow O\leftarrow O OOO或者 O ← O → O O\leftarrow O\rightarrow O OOO,即相邻两者互为出入点。要使得有解存在,则必有偶数条边,这与 n n n为奇数矛盾,假设不成立( a s s e r t   n o   s o l u t i o n s \rm assert\ no\ solutions assert no solutions)。
2021/04/11我校ACM周赛_第2张图片(也就是不存在这样的奇数环)

  • 同时,如果有一个解成立,对于其反边所构成的图也依然成立(有向图)。因此引入染色法(构造二分图)。
#include 
#include 
using namespace std;
const int N = 200010, M = 400010;
int n, m;
int h[N], e[M], ne[M], idx;
int color[N];
void add(int a, int b) {
     
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
bool dfs(int u, int c) {
     
    color[u] = c;
    for (int i = h[u]; ~i; i = ne[i]) {
     
        int j = e[i];
        if (!color[j]) {
     
            if (!dfs(j, 3 - c)) return false;
        }
        else if (color[j] == c) return false;
    }
    return true;
} // module by acwing_yxc...
int main() {
     
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    for (int i = 0; i < m; ++i) {
     
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }
    bool flag = true;
    for (int i = 1; i <= n; i++)
        if (!color[i]) {
     
            if (!dfs(i, 1)) {
     
                flag = false;
                break;
            }
        }
    if (flag) {
      
        printf("YES\n");
        for (int i = 0; i < m << 1; i += 2) {
     
            printf("%d", (color[e[i]] != 1));
        }
    } else {
     
        printf("NO");
    }
    return 0;
}

F. The Number of Pairs

VIEW
题意:对于 t t t组询问,每次给出 c , d , x c,d,x c,d,x,反馈有多少组 ( a , b ) s . t . c × l c m ( a , b ) − d × gcd ⁡ ( a , b ) = x (a,b)\quad s.t. \quad c\times\mathrm{lcm(a,b)} - d\times\gcd(a,b) = x (a,b)s.t.c×lcm(a,b)d×gcd(a,b)=x
制约: c , d , x ∈ [ 1 , 1 0 7 ] , t ∈ [ 1 , 1 0 4 ] c,d,x\in[1,10^7],t\in[1,10^4] c,d,x[1,107],t[1,104]

  • 分析:数论只会gcd(bushi)
  • 原式出现 gcd ⁡ \gcd gcd l c m \rm lcm lcm,一个设为 k k k,另一个则为 k p q ( gcd ⁡ ( p , q ) = 1 ) kpq(\gcd(p,q)=1) kpq(gcd(p,q)=1)
  • 那么原式: c p q − d = x k cpq - d = \dfrac{x}{k} cpqd=kx,不妨设 x : = k y x := ky x:=ky,也即 c p q − d = y ⇒ p q = d + y c : = z cpq-d = y\Rightarrow pq = \dfrac{d+y}{c} := z cpqd=ypq=cd+y:=z
  • 上面提到 gcd ⁡ ( p , q ) = 1 \gcd(p,q)= 1 gcd(p,q)=1,因此对于 z z z,就有 2 n 2^n 2n( n n n z z z质因数分解意义下的最高幂(也就是质因数个数))
  • 因此,就是求质因数个数(欧拉筛的时候搞)之后,枚举判断 z = d + y x z = \dfrac{d+y}{x} z=xd+y是不是整数,形成答案

G. Painting Fence

VIEW

  • 分析:竖着与横着是并列的。对于竖着涂,答案就是这一段区间的长度,在大方向上比较两者谁更优即可。对于横向(也就是上次周赛的「积木大赛」),维护一个动态的 R M Q \rm RMQ RMQ即可(线段树)。

困死了…最后几道先不写了呜呜呜

你可能感兴趣的:(校周赛,字符串,数据结构,算法)