Educational Codeforces Round 12

Educational Codeforces Round 12

A Buses Between Cities

做法:把所有的时间都转换成分钟来考虑这个问题,模拟的情况就很简单了,具体看代码。
代码:

void solve(){
	int a, ta;
	int b, tb;
	cin >> a >> ta >> b >> tb;
	string s;
	cin >> s;
	int tim = ((s[0] - '0') * 10 + (s[1] - '0') ) * 60 + ((s[3] - '0') * 10 + s[4] - '0');
	int timend = tim + ta;
	int ans = 0;
	for (int now = 300;now < 24 * 60;) {
		if(now <= tim && (now + tb) > tim) {
			ans ++;
		}else if(now > tim && now < timend){
			ans++;
		}
		now += b;
	}
	cout << ans << endl;
}

B Shopping

做法:直接看样例模拟,具体的意思就是每次排列会交换位置,输出数的位置权值和,鉴定为样例比题目好看懂。
代码:

void solve(){
	int n , m , k;
	cin >> n >> m >> k;
	vector<int> a(k + 1);
	vector<int> pos(k + 1);
	for (int i = 1;i <= k;i ++) cin >> a[i];
	for (int i = 1;i <= k;i ++) pos[a[i]] = i;
	int ans = 0;
	for (int i = 1;i <= n;i ++) {
		for (int j = 1;j <= m;j ++) {
			vector<int> tmp;
			tmp.push_back(114514);
			int x;
			cin >> x;
			tmp.push_back(x);
			for (int q = 1;q <= k;q ++) {
				if(a[q] != x) {
					tmp.push_back(a[q]);
				}
			}
			// for (int t : tmp) cout << t << ' ';cout << endl;
			for (int i = 1;i <= k;i ++) pos[a[i]] = i;
			a = tmp;
			ans += pos[x];
		}
	}
	cout << ans << endl;
}

C Simple Strings

做法:氵题,模拟。
代码:

void solve(){
	string s;
	cin >> s;
	int n = s.length();
	s = " " + s;
	for (int i = 1;i <= n;i ++) {
		if(s[i - 1] == s[i]) {
			if(i + 1 <= n) {
				for (char op = 'a';op <= 'z';op++) {
					if(op != s[i - 1] && op != s[i + 1]) s[i] = op;
				}
			}
			else {
				for (char op = 'a';op <= 'z';op++) {
					if(op != s[i - 1]) s[i] = op;
				}
			}
		}
	}
	for (int i = 1;i <= n;i ++) cout << s[i];cout << endl;
}

D Simple Subset

做法:需要点神奇思路的题,我们首先考虑这么个情况,假设现在存在三个数,如果其中不含\(1\)的话,是不可能满足题目的要求的,我们可以从奇偶性的角度出发,三个数之中,全为奇或偶必寄,剩下的就是有两个为奇,两个为偶这个样子,那么我们就可以发现,因为奇数加奇数为偶数,偶数不可能为素数,所以,三个数寄。
根据样例知道,我们要特判\(1\),即可解答。
代码:

int primes[N];
bool st[N];
int cnt;
void init() {
	for (int i = 2;i < N;i ++) {
		if(!st[i]) primes[cnt++] = i;
		for (int j = 0;j < cnt && primes[j] * i < N;j ++) {
			st[primes[j] * i] = 1;
			if(i % primes[j] == 0) break;
		}
	}
}
void solve(){
	int n;
	cin >> n;
	vector<int> a(n + 1);
	int cnt1 = 0;
	for (int i = 1;i <= n;i ++) {
		cin >> a[i];
		if(a[i] == 1) cnt1++;
	}
	if(cnt1 == 0 || cnt1 == 1) {
		for (int i = 1;i <= n;i ++) {
			for (int j = i + 1;j <= n;j ++) {
				if(!st[a[i] + a[j]]) {
					cout << 2 << endl;
					cout << a[i] << ' ' << a[j] << endl;
					return ;
				}
			}
		}
		cout << 1 << endl;
		cout << a[1] << endl;
	}
	else {
		for (int i = 1;i <= n;i ++) {
			if(!st[a[i] + 1] && a[i] != 1) {
				cout << cnt1 + 1 << endl;
				for (int i = 1;i <= cnt1;i ++) cout << 1 << ' ';
				cout << a[i] << endl;
				return ;
			}
		}
		cout << cnt1 << endl;
		while(cnt1--) cout << 1 << ' ';cout << endl;
	}
}

E Beautiful Subarrays

做法:队友点评为典,对于这个问题我们可以这么考虑,我们如果把题目要求改成异或值等于\(k\),那么是不是就很简单了,直接前缀异或和等于k,\(O(n)\)的复杂度。但是这里是大于等于\(k\),我们考虑建trie树来考虑异或值,从高到低位进行贪心的选择,如果遍历到的这一位为1的话,因为是从高到底考虑的,所以这一位的异或值必须为\(1\),对于当前的\(R_{i}\),我们走置反的路,\(0\)\(1\)\(1\)\(0\)
如果这一位为\(0\),那我们考虑异或为\(1\)时肯定最优,所以把异或为1时的子树加入贡献,这里trie的cnt统计为经过每个点的数量,即可做出本题。
代码:

int son[N * 30][2];
int cnt[N * 30];
int idx;
int k;
void insert(int x) {
	int p = 0;
	for (int i = 30;i >= 0;i --) {
		int &s = son[p][x >> i & 1];
		if(!s) s = ++idx;
		p = s;
		cnt[p]++;
	}
}
int find(int x) {
	int p = 0;
	int res = 0;
	ll ans = 0;
	for (int i = 30;i >= 0;i --) {
		int ck = (k >> i) & 1;
		if(ck == 1) {
			p = son[p][!(x >> i & 1)];
		}else {
			ans += cnt[son[p][!(x >> i & 1)]];
			p = son[p][(x >> i & 1)];
		}
		if(!p) break;
	}
	ans += cnt[p];
	return ans;
}
void solve(){
	int n;
	cin >> n >> k;
	vector<int> a(n + 1);
	for (int i = 1;i <= n;i ++) cin >> a[i];
	ll s = 0;
	insert(0);
	ll ans = 0;
	for (int i = 1;i <= n;i ++) {
		s ^= a[i];
		ans += find(s);
		insert(s);
	}
	cout << ans << endl;
}

F Four Divisors

做法:这题做法及其简单,难点在于算法。
考虑有四个因子的数,根据因子个数的定理,质因数的次数要么为\(4\)要么为两个\(1\)
所以我们需要的是能做到快速的计算\(\pi(n)\),这里套用了别人的Messiel-Lermer的板子,这个算法现在看的还不是很懂,就是黑盒的用了一下。
代码:

namespace pcf{
    long long dp[MAXN][MAXM];
    unsigned int ar[(MAX >> 6) + 5] = {0};
    int len = 0, primes[MAXP], counter[MAX];
 
    void Sieve(){
        setbit(ar, 0), setbit(ar, 1);
        for (int i = 3; (i * i) < MAX; i++, i++){
            if (!chkbit(ar, i)){
                int k = i << 1;
                for (int j = (i * i); j < MAX; j += k) setbit(ar, j);
            }
        }
 
        for (int i = 1; i < MAX; i++){
            counter[i] = counter[i - 1];
            if (isprime(i)) primes[len++] = i, counter[i]++;
        }
    }
 
    void init(){
        Sieve();
        for (int n = 0; n < MAXN; n++){
            for (int m = 0; m < MAXM; m++){
                if (!n) dp[n][m] = m;
                else dp[n][m] = dp[n - 1][m] - dp[n - 1][m / primes[n - 1]];
            }
        }
    }
 
    long long phi(long long m, int n){
        if (n == 0) return m;
        if (primes[n - 1] >= m) return 1;
        if (m < MAXM && n < MAXN) return dp[n][m];
        return phi(m, n - 1) - phi(m / primes[n - 1], n - 1);
    }
 
    long long Lehmer(long long m){
        if (m < MAX) return counter[m];
 
        long long w, res = 0;
        int i, a, s, c, x, y;
        s = sqrt(0.9 + m), y = c = cbrt(0.9 + m);
        a = counter[y], res = phi(m, a) + a - 1;
        for (i = a; primes[i] <= s; i++) res = res - Lehmer(m / primes[i]) + Lehmer(primes[i]) - 1;
        return res;
    }
}
void solve(){
	int n;
	pcf::init();
	cin >> n;
	int ans = 0;
	for (int i = 0;i < pcf::len;i ++) {
		int p = pcf::primes[i];
		int y = n / p;
		if(p > sqrt(n)) break;
		else ans += pcf::Lehmer(y) - pcf::Lehmer(p);
	}
	for (int i = 0;i < pcf::len;i++) {
		int p = pcf::primes[i];
		if(p * p * p > n) break;
		else ans++;
	}
	cout << ans << endl;
}
 
posted @ 2023-01-13 18:06  zwhqwq  阅读(36)  评论(0编辑  收藏  举报