2019 China Collegiate Programming Contest Qinhuangdao Onsite

Contest Info


[Practice Link](https://codeforces.com/gym/102361)
Solved A B C D E F G H I J K L
5/12 O - - O - O - - - O Ø -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Angle Beats

题意:
给出\(n\)个点,每次询问再给出一个点,询问\(n\)个点中与当前这个点构成直角三角形的方案数。

D. Decimal

题意:
给出一个\(n\),判断\(\frac{1}{n}\)是否是一个无限循环小数。

思路:
如果\(n\)的质因子分解是\(2^x5^y\)那么不是无限循环

代码:

view code
#include <bits/stdc++.h>
#define debug(...) { printf("#  "); printf(__VA_ARGS__); puts(""); }
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }
inline void pt() { cout << endl; }
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); }
template <class T> inline void pt(const T &s) { cout << s << "\n"; }
template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } 
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
constexpr int N = 1e5 + 10;
int n; 
void run() {
	cin >> n;
	while (n % 2 == 0) n /= 2;
	while (n % 5 == 0) n /= 5;
	if (n == 1) pt("No");
	else pt("Yes");
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	int _T; cin >> _T;
	while (_T--) run();
	return 0;
}

F. Forest Program

题意:
给出一个无向图,每条边最多存在于一个环中,问多少种移除边的方案使得剩下的每一个连通块都是一棵树

思路:
一个环,这个环上至少要切一条边,其他边任意切不切。
注意刚开始给出的可能不是连通图。

代码:

view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long; 
const int N = 5e5 + 10;
const ll mod = 998244353;
int n, m, bit[N];
vector <vector<int>> G;
int dep[N], tot, vis[N], Insta[N]; ll res;
void dfs(int u, int pre) {
	vis[u] = 1;
	Insta[u] = 1;
	for (auto &v : G[u]) if (v != pre) {   
		if (Insta[v]) { 
			tot -= dep[u] - dep[v] + 1; 
			res = 1ll * res * (bit[dep[u] - dep[v] + 1] - 1) % mod;
			res %= mod;
		}
		if (!vis[v]) {
			dep[v] = dep[u] + 1;
			dfs(v, u);
		}
	}
	Insta[u] = 0;
}
 
int main() {
	bit[0] = 1;
	for (int i = 1; i < N; ++i) bit[i] = 1ll * bit[i - 1] * 2 % mod;
	while (scanf("%d%d", &n, &m) != EOF) {
		G.clear(); G.resize(n + 1);
		for (int i = 1; i <= n; ++i) dep[i] = vis[i] = Insta[i] = 0;
		for (int i = 1, u, v; i <= m; ++i) {
			scanf("%d%d", &u, &v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		tot = m; res = 1; 
		for (int i = 1; i <= n; ++i) if (!vis[i]) dfs(i, i);
		res = 1ll * res * bit[tot] % mod;
		res = (res + mod) % mod;
		printf("%lld\n", res);
	}
	return 0;
}

I. Invoker

题意:
每种技能需要三种属性,三个属性被按下就可以触发,而顺序不重要。
但是每次只能保留三个属性,按下第四个的时候第一个会被移除。
现在给出一个需要使用的技能表,询问怎样按键使得按顺序出发这些技能并且按下的次数最少。

思路:
考虑每种技能最多只有六种排列状态,那么\(f[i][S]\)表示前\(i\)个技能,当前排列状态为\(S\)的最少按键数。

代码:

view code
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
char s[N]; int n;
map <string, int> f[2];
map <char, string> mp;

int main() {
    mp['Y'] = "QQQ";
    mp['V'] = "QQW";
    mp['G'] = "EQQ";
    mp['C'] = "WWW";
    mp['X'] = "QWW";
    mp['Z'] = "EWW";
    mp['T'] = "EEE";
    mp['F'] = "EEQ";
    mp['D'] = "EEW";
    mp['B'] = "EQW";
    while (scanf("%s", s + 1) != EOF) {
        f[0].clear(), f[1].clear();
        int n = strlen(s + 1);
        for (int i = 1; i <= n; ++i) {
            int p = i & 1;
            if (i > 1 && s[i] == s[i - 1]) {
                f[p] = f[p ^ 1];
                continue;
            }
            f[p].clear();
            string s1 = mp[s[i]];
        //    cout << s1 << endl;
            do {
                if (i == 1) {
                    f[p][s1] = 3;
                    continue;
                }
                f[p][s1] = 1e9; 
                for (auto &it : f[p ^ 1]) {
                    string s2 = it.first;
                //    cout << s1 << " " << s2 << endl;
                    int w = it.second;
                    if (s2[1] == s1[0] && s2[2] == s1[1]) {
                        f[p][s1] = min(f[p][s1], w + 1);
                    } else if (s2[2] == s1[0]) {
                        f[p][s1] = min(f[p][s1], w + 2);
                    } else {
                        f[p][s1] = min(f[p][s1], w + 3);
                    }
                }
            }while (next_permutation(s1.begin(), s1.end()));
        }
        int res = 1e9;
        for (auto &it : f[n & 1]) {
        //    cout << it.first << " " << it.second << endl;
            res = min(res, it.second);
        }
        printf("%d\n", res + n);
    }
    return 0;
}

J. MUV LUV EXTRA

题意:
给出一个小数,询问小数部分后缀中的\(a \cdot p - b \cdot l\)的最大值。
\(a, b\)是参数,\(p\)表示循环节长度,\(l\)表示后缀长度

思路:
将字符串翻转,用\(kmp\)找循环节即可。

代码:

view code
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e7 + 10;
ll a, b;
char s[N], t[N]; int n;
void get() {
    int i;
    for (i = 1; s[i]; ++i) {
        if (s[i] == '.') break;
    }
    n = 0;
    for (++i; s[i]; ++i) {
        t[n++] = s[i];
    }
    t[n] = 0;
}
struct KMP {
    int Next[N];
    //下标从0开始
    void get_Next(char *s) {
        int len = strlen(s);  
        int i, j;
        j = Next[0] = -1;
        i = 0;
        while (i < len) {
            while (-1 != j && s[i] != s[j]) j = Next[j];
            Next[++i] = ++j;
        }
    }
}kmp;

int main() {
    while (scanf("%lld%lld", &a, &b) != EOF) {
        scanf("%s", s + 1);
        get();
        reverse(t, t + n); t[n] = 0;
        kmp.get_Next(t);
        ll res = a - b; 
        for (int i = 1; i < n; ++i) {
            ll p = i + 1;
        //    cout << i << " " << kmp.Next[i + 1] << endl;
            ll l = p - kmp.Next[i + 1];
            res = max(res, a * p - b * l);
        }    
        printf("%lld\n", res);
    }
    return 0;
}
posted @ 2019-10-22 09:46  Dup4  阅读(582)  评论(0编辑  收藏  举报