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)=maxl≤x≤y≤rf(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;
}