2022年多校冲刺NOIP联训测试7
A. 计算器
搜索,因为某种装备选一定比不选优,所以对每种装备考虑选什么即可,注意如果用\(vector\)等,对于不存在的装备类型不应该继续搜索,即使直接跳过,如果在搜索树最后一层每个节点都挂一条链,复杂度也是难以接受的
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 53;
inline int read(){
int x = 0; char c = getchar();
while(c > '9' || c < '0')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
int n, k;
struct node{
int tp,a,b,c,d;
}a[maxn];
bool cmp(node x, node y){return x.tp < y.tp;}
ll ans, sa, sb, sc, sd;
void dfs(int x){
if(x > n){
ans = max(ans, (sa + 100) * (sb + 100) * (sc + 100) * (sd + 100));
return;
}
int l = x, r = x;
while(r < n && a[r + 1].tp == a[l].tp) ++r;
for(int i = l; i <= r; ++i){
sa += a[i].a;
sb += a[i].b;
sc += a[i].c;
sd += a[i].d;
dfs(r + 1);
sa -= a[i].a;
sb -= a[i].b;
sc -= a[i].c;
sd -= a[i].d;
}
}
int main(){
n = read(), k = read();
for(int i = 1; i <= n; ++i)
a[i].tp = read(), a[i].a = read(), a[i].b = read(), a[i].c = read(), a[i].d = read();
sort(a + 1, a + n + 1, cmp);
dfs(1);
printf("%lld\n",ans);
return 0;
}
B. 对称轴
暴力枚举对称轴加上一点优化就能卡过,正解是\(hash\)判断回文,元素是边和角
code
// #pragma GCC optimize(3)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100005;
const double eps = 0.01;
inline int read(){
int x = 0; char c = getchar(); bool f = 0;
while(c > '9' || c < '0'){if(c == '-')f = 1;c = getchar();}
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
if(f) x = -x;
return x;
}
int n;
inline bool equal(double x,double y){return x + eps >= y && x - eps <= y;}
struct node{double x,y;}a[maxn];
inline node MID(int x,int y){
node ans;
ans.x = 0.5 * (a[x].x + a[y].x);
ans.y = 0.5 * (a[x].y + a[y].y);
return ans;
}
inline bool chuizhi(node x, node y, double k){
return equal(k ,0) ? equal(x.x, y.x) : equal((x.y - y.y) * k, - x.x + y.x);
}
int ans;
inline int check_x(double dx, int ll, int rr){
int l = ll, r = rr;
while(1){
--l;if(l == 0)l = n;
if(l == r && r != rr)return 1;
++r;if(r == n + 1)r = 1;
node mid = MID(l, r);
if(! (a[l].y == a[r].y && equal(mid.x, dx)))return 0;
if(l == r)return 1;
}
}
inline int check(double k, double b, int ll, int rr){
int l = ll, r = rr;
while(1){
--l;if(l == 0)l = n;
if(l == r && r != rr)return 1;
++r;if(r == n + 1)r = 1;
if(l == r)return 1;
node mid = MID(l, r);
if(!(equal(mid.y, mid.x * k + b) && (l == r || chuizhi(a[l],a[r],k))))return 0;
}
}
int main(){
int T = read();
for(register int i = 1;i <= T; ++i){
n = read();
for(register int j = 1; j <= n; ++j)a[j].x = read(), a[j].y = read();
ans = 0;
if(n & 1){
for(register int i = 1; i <= n; ++i){
int l = i - 1, r = i + 1;
if(l == 0)l = n;
if(r == n + 1) r = 1;
node mid = MID(l, r);
if(equal(mid.x, a[i].x))ans += check_x(a[i].x, i, i);
else{
double k = (mid.y - a[i].y) / (mid.x - a[i].x);
double b = mid.y - k * mid.x;
ans += check(k, b, i, i);
}
}
}else{
int hf = n / 2;
for(register int i = 1; i <= hf; ++i){
int l = i - 1, r = i + 1;
if(l == 0)l = n;
if(r == n + 1) r = 1;
node mid = MID(l, r);
if(equal(mid.x, a[i].x))ans += check_x(a[i].x, i, i);
else{
double k = (mid.y - a[i].y) / (mid.x - a[i].x);
double b = mid.y - k * mid.x;
int dm = (i + hf) % n;
if(dm == 0)dm = n;
if(equal(k * a[dm].x + b , a[dm].y))ans += check(k, b, i, i);
}
}
for(register int l = 1; l <= hf; ++l){
int r = l + 1; if(r == n + 1) r = 1;
node mid = MID(l, r);
int ll = l - 1, rr = r + 1;
if(ll == 0)ll = n;
if(rr == n + 1)rr = 1;
node mid2 = MID(ll, rr);
if(equal(mid.x, mid2.x))ans += check_x(mid2.x, l + 1, r - 1);
else{
double k = (mid.y - mid2.y) / (mid.x - mid2.x);
double b = mid.y - k * mid.x;
ans += check(k, b, l + 1, r - 1);
}
}
}
printf("%d\n",ans);
}
return 0;
}
C. 互质
傻了傻了,莫反没看出来
如果区间已知,那么
\(\displaystyle ans = \sum_{i = 1}^{maxn}[gcd(i ,x) == 1]cnt_i\)
\(\displaystyle = \sum_{i = 1}^{maxn}\sum_{d|gcd(i, x)}\mu(d)cnt_i\)
\(\displaystyle = \sum_{d| x}\mu(d)\sum_{i = 1}^{maxn/d}cnt_{id}\)
令
\(\displaystyle f(d) = \sum_{i = 1}^{maxn/d}cnt_{id}\)
答案为
\(\displaystyle \sum_{d| x}\mu(d)f(d)\)
把询问拆成两个前缀询问,相减得到答案,这样我们只需要维护类似前缀和的东西
那么自然而然想到可持久化
然而主席树会\(MLE\),但是其实我们并不需要完全可持久化,部分即可,用\(vector\)维护每个\(f\)被修改的时间,每次\(lower\_bound\)即可
code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 100005;
inline int read() {
int x = 0;
char c = getchar();
while (c > '9' || c < '0') c = getchar();
do {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
} while (c >= '0' && c <= '9');
return x;
}
vector<int> y[maxn], f[maxn];
bool flag[maxn];
int prime[maxn], cnt, mu[maxn];
int n, m, op;
int query(int x, int l, int r) {
int ans = 0;
for (int i : y[x]) {
int si = f[i].size();
if (si == 0) continue;
int now = lower_bound(f[i].begin(), f[i].end(), r) - f[i].begin();
int las = lower_bound(f[i].begin(), f[i].end(), l - 1) - f[i].begin();
if (now < si && f[i][now] == r) ++now;
if (las < si && f[i][las] == l - 1) ++las;
ans += mu[i] * (now - las);
}
return ans;
}
int main() {
mu[1] = 1;
for (int i = 2; i <= 100000; ++i) {
if (!flag[i]) {
prime[++cnt] = i;
mu[i] = -1;
}
for (int j = 1; j <= cnt && i * prime[j] <= 100000; ++j) {
flag[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= 100000; ++i) {
if (mu[i] == 0) continue;
for (int j = i; j <= 100000; j += i) y[j].push_back(i);
}
n = read();
m = read();
op = read();
for (int i = 1; i <= n; ++i) {
int x = read();
for (int j : y[x]) f[j].push_back(i);
}
int ans = 0;
for (int i = 1; i <= m; ++i) {
int l = read(), r = read(), x = read();
l ^= (op * ans);
r ^= (op * ans);
x ^= (op * ans);
printf("%d\n", ans = (query(x, l, r)));
}
return 0;
}
D. 签到题
奇妙的性质,\(vizing\)定理啥的,不要想太多直接莽就完了
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e6 + 55;
inline int read(){
int x = 0; char c = getchar();
while(c > '9' || c < '0')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
int n, m, k, c, l[maxn], r[maxn];
int main(){
n = read(), m = read(), k = read(), c = read();
for(int i = 1; i <= k; ++i)++l[read()], ++r[read()];
int ans = 0;
for(int i = 1; i <= n; ++i)ans += l[i] % c == 0 ? 0 : 1;
for(int i = 1; i <= m; ++i)ans += r[i] % c == 0 ? 0 : 1;
printf("%d\n",ans);
return 0;
}