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;
}