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;
}
posted @ 2022-08-01 10:46  Chen_jr  阅读(77)  评论(24编辑  收藏  举报