Codeforces Round #705 (Div. 2)

A

[ ( k + 1 ) / 2 , n ] ∩ N − { k } [(k+1)/2, n] \cap \N- \{k\} [(k+1)/2,n]N{k} 为答案集合.

int n, k;
 
void solve() {
	qr(n, k);
	int l = (k + 1) / 2;
	V<int> ans;
	rep(i, l, n) if(i ^ k) ans.pb(i);
	pr2(SZ(ans));
	for(int i:ans) pr1(i);
	puts(""); 
}

B

模拟一下.

int h, m, a, b;
bool v[11];
 
 
bool check(int x) {
	return !v[x % 10] && !v[x / 10];
}
int r[11]={0,1,5,0,0,2,0,0,8,0};
int rev(int x) {
	return r[x % 10] * 10 + r[x / 10];
}
 
void solve() {
	v[3] = v[4] = v[6] = v[7] = v[9] = 1;
	qr(h, m);
	qr(a, b);
	while(1) {
		if(check(a) && check(b) && rev(a) < m && rev(b) < h) {
			printf("%02d:%02d\n", a, b);
			return ;
		}
		b++;
		if(b == m) {
			b = 0;
			if(++a == h) a = 0;
		}
	}
}

C

因为要字典序最小, 所以我们从后往前枚举第一个变大的位置.
然后后面全部填尽量小即可.

int n, k, cnt[28], c[28], pre[N][28];
char s[N], ans[N];
 
bool check() { rep(i, 0, 25) if(cnt[i] % k) return 0; return 1;}
bool check(int x) {
	int s = 0;
	rep(i, 0, 25) {
		if(cnt[i] % k) {
			s += c[i] = k - cnt[i] % k;
		}
		else c[i] = 0;
		if(s > n - x) return 0;
	}
	c[0] += n - x - s;
	rep(i, x + 1, n)
		rep(j, 0, 25) 
			if(c[j]) {ans[i] = j + 'a'; c[j]--; break;}
	puts(ans + 1); return 1;
}
 
void solve() {
	qr(n, k); scanf("%s", s + 1);
	if(n % k) {puts("-1"); return;}
	memset(cnt, 0, sizeof cnt);
	memset(c, 0, sizeof c);
	FOR(i, n) ans[i] = s[i], cnt[s[i] -= 'a']++;
	ans[n + 1] = 0; 
	if(check()) {puts(ans + 1); return ;}
	FOR(i, n) {
		memcpy(pre[i], pre[i - 1], sizeof pre[i]);
		pre[i][s[i]]++;
	}
	REP(i, 1, n) {
		int x = s[i]; 
		memcpy(cnt, pre[i - 1], sizeof cnt);
		rep(j, x + 1, 25) {
			ans[i] = j + 'a';
			cnt[j]++;
			if(check(i)) return ;
			cnt[j]--;
		}
	}
}
 

D

每个数不超过 log ⁡ a i \log a_i logai 个质因子.
我们对每个质因子维护最小指数.
为了不爆空间, 我们使用 multiset \text{multiset} multiset 维护即可.
总复杂度为 O ( ( n + m ) log ⁡ 2 n ) O((n+m)\log^2 n) O((n+m)log2n).

int n, q, a[N], prime[N], tot, v[N], ID[N];
ll ans = 1;
struct rec {
	int p;
	multiset<int> s;
	map<int, int> ex;//exponent
	int Min() {return SZ(s) == n ? *s.begin() : 0;}
	void add(int x, int c) {
		int st = Min();
		if(ex[x]) s.erase(s.find(ex[x]));
		ex[x] += c;
		s.insert(ex[x]);
		int ed = Min();
		while(st < ed) ans = ans * p % mod, st++;
	}
} S[N];
 
void ins(int x, int y) {
	while(y ^ 1) {
		int P = v[y], e = 0;
		while(y % P == 0) y /= P, e++;
		S[ID[P]].add(x, e);
	}
}
 
void solve() {
	n = 2e5; v[1] = 1;
	rep(i, 2, n) {
		if(!v[i]) prime[++tot] = v[i] = i, S[tot].p = i, ID[i] = tot;
		for(int j = 1, k; (k = i * prime[j]) <= n; j++) {
			v[k] = prime[j];
			if(i % prime[j] == 0) break;
		}
	}
	qr(n, q);
	FOR(i, n) qr(a[i]), ins(i, a[i]);
	int i, x; while(q--) {
		qr(i, x); 
		ins(i, x);
		pr2(ans);
	}
}

E

昨天用一个奇怪做法过了,但是今天学了一下正解(
首先, 对于 l , r l,r l,r 最高位不同的方案, 答案一定为 1...1 ( n ) 1...1(n) 1...1(n).
否则,一定取了奇数个数.
g ( l , r ) = max ⁡ l ≤ x ≤ y ≤ r f ( x , y ) g(l, r) = \max_{l\le x\le y\le r}f(x, y) g(l,r)=maxlxyrf(x,y).
然后可以发现, 当末位置 r r r为偶数时, 可以选择至少3个数, 则 g ( l , r ) = r + 1 g(l,r)=r+1 g(l,r)=r+1.(除了最低位其他都可以抵消).
r r r为奇数时, 我们可以用归纳法证明 g ( l , r ) = r g(l,r)=r g(l,r)=r.
每次只需要从 r r r归纳到 r + 2 r+2 r+2即可.

int n; string a, b, c;
 
void solve() {	
	cin >> n >> a >> b;
	if(a[0] != b[0]) c = string(n, '1');
	else {
		c = b; int i = 1; while(i < n && a[i] == b[i]) i++;
		rep(j, i + 1, n - 1) if(a[j] == '0' || b[j] == '1') c[n - 1] = '1';
	}
	cout << c << "\n";
}

F

两个维度独立.
我们一边长判断是否可以除一个质数 P P P.
可以发现当 P = 2 P=2 P=2时, 一步判断即可.
否则需要拆成3段,判断两次.
用换底公式可以发现这个 3 log ⁡ n + m 3\log{n+m} 3logn+m是很松的上界.

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = a; i <= b; i++)
using namespace std;
 
int n, m, f;
int ask(int len, int a, int b) {
	if(!f) printf("? %d %d %d 1 %d 1\n", len, m, a, b);
	else printf("? %d %d 1 %d 1 %d\n", n, len, a, b);
	fflush(stdout); scanf("%d", &a); return a;
}
 
bool check(int x, int y) {
	if(y == 2) return ask(x / y, 1, x / y + 1);
	int w = (y / 2) * (x / y);
	return ask(w, 1, w + 1) && ask(w, 1, w + 1 + x / y);
}
	
int a[9], b[9], tot;
int solve(int x) {
	tot = 0; int y = x;
	rep(i, 2, x) if(x % i == 0) {
		a[++tot] = i; b[tot] = 0;
		while(x % i == 0) b[tot]++, x /= i;
	}
	int sum = 1, res = 1;
	rep(i, 1, tot) 
		rep(j, 1, b[i]) {
			if(check(y / sum, a[i])) 
				sum *= a[i], res = res / j * (j + 1);
			else break;
		}
	return res;
}
 
int main() {
	scanf("%d %d", &n, &m);
	int ans = solve(n);
	f = 1; ans *= solve(m); cout << "! " << ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值