「csp模拟」模拟测试1

  • 分很低呀,暴力分打的不足,别人的T1暴力70+,我只有50。 T3的部分分也没有拿够,还有有几种比较简单的情况没有考虑到。
  • 图论的题目总是想不到暴力,或者是想到了暴力总有细节出问题,以后注意吧。

平凡的函数

题目描述

题解

直接线性筛即可, 然后记录一下质因子的幂数。

code

#include <cstdio>
#include <cctype>
#include <cmath>
#include <iostream>
using namespace std;
#define print(x) cerr << #x << " : " << x << endl;
inline int read() {
    int k = 0, f = 1; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
    return k * f;
}
const int maxn = 5e7 + 100;
int prime[maxn], vis[maxn], f[maxn];
signed main() {
#ifdef local
    freopen("in", "r", stdin);
#else
    freopen("func.in", "r", stdin);
    freopen("func.out", "w", stdout);
#endif
    int n = read(), cnt = 0;
    long long ans = 1;
    f[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) prime[++cnt] = i, f[i] = i ^ 1;
        for (int j = 1; i * prime[j] <= n; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                int x = i, m = 1;
                while (x % prime[j] == 0) x /= prime[j], ++m;
                f[i * prime[j]] = f[x] * (prime[j] ^ m);
                break;
            }
            f[i * prime[j]] = f[i] * f[prime[j]];
        }
        ans += f[i];
    }
    printf("%lld\n", ans);
    return 0;
}

那一天她离我而去

题目描述

她走的悄无声息,消失的无影无踪。
至今我还记得那一段时间,我们一起旅游,一起游遍山水。到了最终的景点,她却悄无声息地消失了,只剩我孤身而返。
现在我还记得,那个旅游区可以表示为一张由n个节点m条边组成无向图。我故地重游,却发现自己只想尽快地结束这次旅游。我从景区的出发点(即 1 号节点)出发,却只想找出最短的一条回路重新回到出发点,并且中途不重复经过任意一条边。
即:我想找出从出发点到出发点的小环。

题解

  • 暴力思路:将所有与起点相连的边删除,从这些相连的点跑到其他相连点的最短路尝试更新答案
  • 正解思路:对暴力进行优化,分组进行最短路, 因为任意两个不同的点,二进制一定至少存在一位不同,我们以每个二进制位的0,1进行分组,每组点组成的环一定被至少一次更新,于是可以达到目的, 复杂度 \(O(m log^2n)\)

code

暴力
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5, maxm = 4e4 + 5;
const int Inf = 0x3f3f3f3f;
struct node { int to, next, dis; } e[maxm<<1];
int head[maxn], ecnt;
void add(int a,int b,int c){ e[ecnt] = (node){b, head[a], c}; head[a] = ecnt++; }
int vis[maxn], dis[maxn];
void Spfa(int x){
    memset(dis,0x3f,sizeof(dis));    
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(x); dis[x]=0;
    while(!q.empty()){
        int u = q.front(); q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i=e[i].next){
            int v = e[i].to, d;
            if(dis[v] > (d = dis[u] + e[i].dis)) {
                dis[v] = dis[u] + e[i].dis;
                if(!vis[v]) q.push(v), vis[v] = 1;
            }
        }
    } 
}
int main(){
#ifndef debug
    freopen("leave.in", "r", stdin);
    freopen("leave.out", "w", stdout);
#endif
    int T; scanf("%d",&T);
    while(T--){
        int n, m; scanf("%d%d", &n, &m);
        memset(head, -1, sizeof(head));
        ecnt = 0;
        for(int i = 1; i <= m; i++){
            int u, v, dis; scanf("%d%d%d", &u, &v, &dis);
            add(u, v, dis), add(v, u, dis);
        }
        int ans = Inf;
        for(int i = head[1]; ~i; i = e[i].next) {
            int temp = e[i].dis;
            e[i].dis = e[i ^ 1].dis = Inf;
            Spfa(1);
            ans = std::min(ans, dis[e[i].to] + temp);
            e[i].dis = e[i ^ 1].dis = temp;
        }
        if(ans == Inf) printf("-1\n");
        else printf("%d\n", ans);
    }
}

正解
#include <bits/stdc++.h>
using namespace std;
#define print(x) cerr << #x << " : " << x << endl;
inline int read() {
    int k = 0, f = 1; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
    return k * f;
}
const int maxn = 3e4 + 100;
struct node { int to, next, dis; } e[maxn * 8];
struct edge { int to, dis; } g[maxn * 8];
int head[maxn], ecnt = 0;
inline void add(int u, int v, int d) { e[++ecnt] = (node) {v, head[u], d}; head[u] = ecnt; }
int dis[maxn], vis[maxn];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
inline void dijkstra(int s) {
    memset(vis, 0, sizeof(vis)), memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    q.push(make_pair(0, s));
    while (q.size()) {
        int x = q.top().second;
        q.pop();
        if (vis[x]) continue;
        for (register int i = head[x]; i; i = e[i].next) {
            int y = e[i].to, d;
            if (dis[y] > (d = dis[x] + e[i].dis)) {
                dis[y] = d;
                q.push(make_pair(dis[y], y));
            }
        }
    }
}
int main() {
#ifndef debug
    freopen("leave.in", "r", stdin);
    freopen("leave.out", "w", stdout);
#endif
    int T = read();
    while(T--) {
        int n = read(), m = read();
        memset(head, 0, sizeof(head));
        ecnt = 1;
        int ans = 0x3f3f3f3f;
        int gcnt = 0;
        for (register int i = 1; i <= m; i++) {
            int x = read(), y = read(), z = read();
            if(x > y) swap(x, y);
            if(x == 1) g[++gcnt] = (edge){y, z};
            else add(x, y, z), add(y, x, z);
        }
        int tot = n;
        for(int i = 1; i <= n; i <<= 1) {
            int s = ++tot, t = ++tot;
            for(int j = 1; j <= gcnt; j++) {
                if(g[j].to & i) add(s, g[j].to, g[j].dis);
                else add(g[j].to, t, g[j].dis);
            } 
            dijkstra(s);
            ans = min(ans, dis[t]);
        }
        if (ans == 0x3f3f3f3f) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}

熟练剖分(tree)

题目描述


题解

  • 复制一份标准题解
    容易发现总方案数为所有节点的儿子个数的乘积。
    可以计算每个时间代价的方案数是多少,最后算出总答案,除掉总方案数就是期望。
    这个东西可以通过 dp 来计算,设 \(dp_{i,j}\) 表示节点 \(i\) 子树中最坏时间代价为 \(j\) 的方案数。
    在归并子树的过程中,给 dp 数组多加一维,表示是否已经选择过重儿子即可。

coding ...

posted @ 2020-09-25 09:28  hyskr  阅读(210)  评论(0编辑  收藏  举报