2020 CCPC-Wannafly Winter Camp Day3

PTA
牛客

A. 黑色气球

数据保证答案唯一,则随便搞搞即可。


Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e3+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;

int n,h[MAXN][MAXN];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>h[i][j];
        }
    }
    int a =  (h[1][2] + h[1][3] - h[2][3]) / 2;
    cout <<a<<' ';
    for(int i=2;i<=n;i++){
        cout << h[1][i]-a<<" \n"[i==n];
    }
    return 0;
}

D. 求和

接下来是推式子时间:
\[ \begin{aligned} f(n)=&\sum_{i=1}^n\sum_{j=1}^ngcd(i,j,n)\\ =&\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j,n)=d]\\ =&\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^n[gcd(\frac{i}{d},\frac{j}{d},\frac{n}{d})=1]\\ =&\sum_{d=1}^nd\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}[gcd(i,j,\frac{n}{d})=1]\\ =&\sum_{d=1,d|n}^nd\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}\sum_{k|i,k|j,k|\frac{n}{d}}\mu(k)\\ =&\sum_{k}\mu(k)\sum_{d|n,d|\frac{n}{k}}(\frac{n}{kd})^2d\\ =&\sum_{T|n}(\frac{n}{T})^2\sum_{d|T}d\mu(\frac{T}{d})\\ =&\sum_{T|n}(\frac{n}{T})^2\varphi(T) \end{aligned} \]

\[ f(i)=\sum_{T|i}(\frac{i}{T})^2\varphi(T) \]

\[ \begin{aligned} \sum_{i=1}^nf(i)=&\sum_{i=1}^n\sum_{T|i}(\frac{i}{T})^2\varphi(T)\\ =&\sum_{T=1}^n\varphi(T)\sum_{i=1}^{\frac{n}{T}}i^2 \end{aligned} \]
所以杜教筛预处理\(\varphi\)的前缀和,然后整除分块即可。
代码如下:


Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 5;
int mu[N], p[N];
ll phi[N];
bool chk[N];
unordered_map <int, ll> mp1, mp2;
int MOD, inv6;
ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;  
    }
    return ans;  
}
void init() {
    inv6 = qpow(6, MOD - 2);
    phi[1] = 1;
    int cnt = 0, k = N - 1;
    for(int i = 2; i <= k; i++) {
        if(!chk[i]) p[++cnt] = i, mu[i] = -1, phi[i] = i - 1;
        for(int j = 1; j <= cnt && i * p[j] <= k; j++) {
            chk[i * p[j]] = 1;
            if(i % p[j] == 0) {phi[i * p[j]] = phi[i] * p[j] % MOD; break;}
            phi[i * p[j]] = phi[i] * (p[j] - 1) % MOD;
        }
    }
    for(int i = 1; i < N; i++) {
        phi[i] = (phi[i - 1] + phi[i]) % MOD;
    }
}

ll djs_phi(int n) {
    if(n <= 5000000) return phi[n];
    if(mp2[n]) return mp2[n];
    ll ans = 1ll * (n + 1) * n / 2 % MOD;
    for(int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        ans -= 1ll * (j - i + 1) * djs_phi(n / i) % MOD;
        if(ans < 0) ans += MOD;
    }
    return mp2[n] = ans;
}
int n;
int S(int n) {
    return 1ll * n * (n + 1) % MOD * (2 * n + 1) % MOD * inv6 % MOD;
}
int main() {
    cin >> n >> MOD;
    init();
    int ans = 0;
    for(int i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        int up = n / i;
        int res = S(up);
        ans = (ans + 1ll * res * (djs_phi(j) - djs_phi(i - 1) + MOD) % MOD) % MOD;   
    }
    cout << ans << '\n';
    return 0;
}

E. 棋技哥

存在一个结论,只要左上角为黑,则火山哥必胜。
因为火山哥赢的充要条件为游戏最终进行奇数轮就结束,那么必然\((1,1)\)初始为黑才行。


Code

#include<bits/stdc++.h>
using namespace std;
char s[2333];
int main() {
    int t; scanf("%d", &t);
    while(0<t--) {
        bool ac=false;
        int n,m; scanf("%d%d", &n, &m);
        for(int i=0; i<n; i++) {
            scanf("%s", s);
            if(i==0 && s[0]=='1') ac=true;
        }
        if(ac) puts("call");
        else puts("aoligei");
    }
    return 0;
}

F. 社团管理

决策单调性\(dp\),还不会,填坑。


Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e5+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;

int n,k,a[MAXN],c[MAXN];
ll f[MAXN],g[MAXN];
void solve(int l,int r,int L,int R,ll w){
    if(l>r)return ;
    int m = (l+r)>>1,k=0,p=m<R?m:R;
    for(int i=l;i<=m;i++)w+=c[a[i]]++;
    for(int i=L;i<=p;i++){
        w-=--c[a[i]];
        if(l== n&& r==n){
            //cout <<n<<' '<<i<<' '<<f[i]<<' '<<w<<'\n';
        }
        if(g[m] > f[i] + w){
            g[m] = f[i] + w;
            k=i;
        }
    }
    for(int i=L;i<=p;i++){
        w += c[a[i]]++;
    }
    for(int i=l;i<=m;i++)w-=--c[a[i]];
    solve(l,m-1,L,k,w);

    for(int i=l;i<=m;i++)w+=c[a[i]]++;
    for(int i=L;i<k;i++)w-=--c[a[i]];
    solve(m+1,r,k,R,w);
    for(int i=L;i<k;i++)++c[a[i]];
    for(int i=l;i<=m;i++)--c[a[i]];
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        f[i] = f[i-1] + c[a[i]]++;
    }
    memset(c,0,sizeof(c));
    while(--k){
        memset(g,0x3f,sizeof(g));
        solve(1,n,1,n,0);
        swap(f,g);
    }   
    cout<<f[n]<<'\n';
    return 0;
}

G. 火山哥周游世界

容易分析,最终火山哥的路线会经历每条必走的边两次,某条链可以只经过一次。
那么直接换根\(dp\)处理出离所有结点长度最长的链。之后再换根\(dp\)求出每个结点作为根时,到达所有关键点的边权和乘以\(2\)的值。二者相减即为每个结点作为根时的情况。
代码实现起来较为复杂,细节见代码。主要是维护最长链时要维护最长和次长链,这样就比较方便转移。


Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/1/14 14:23:18
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e5 + 5;

int n, k;

struct Edge {
    int v, w, next;   
}e[N << 1];
int head[N], tot;
void adde(int u, int v, int w) {
    e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
}
bool chk[N];
int sz[N];
ll f[N][2], g[N][2], L[N];
ll ans[N];

void dfs(int u, int fa) {
    sz[u] = (chk[u] == true);
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v, w = e[i].w; 
        if(v == fa) continue;
        dfs(v, u);
        sz[u] += sz[v];
    }
}

void dfs2(int u, int fa) {
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v, w = e[i].w;
        if(v == fa) continue;
        dfs2(v, u);
        if(sz[v]) {
            ans[u] += ans[v] + w;
            if(f[v][0] + w > f[u][0]) {
                f[u][1] = f[u][0];
                g[u][1] = g[u][0];
                f[u][0] = f[v][0] + w;
                g[u][0] = v;
            } else if(f[v][0] + w > f[u][1]) {
                f[u][1] = f[v][0] + w;
                g[u][1] = v;   
            }
        }
    }   
}

void dfs3(int u, int fa, ll h) {
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v, w = e[i].w;
        if(v == fa) continue;
        ll mx;
        if(g[u][0] == v) mx = max(h, f[u][1]);
        else mx = max(h, f[u][0]);
        L[v] = max(f[v][0], mx + w);
        dfs3(v, u, mx + w);
    }   
}

void dfs4(int u, int fa) {
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v, w = e[i].w;
        if(v == fa) continue;
        ans[v] = ans[u] - 2ll * (sz[v] > 0) * w + 2ll * (k - sz[v] > 0) * w;
        dfs4(v, u);
    }   
}

void run(){
    memset(head, -1, sizeof(head)); tot = 0;
    for(int i = 1; i < n; i++) {
        int u, v, w; cin >> u >> v >> w;
        adde(u, v, w); adde(v, u, w);
    }
    for(int i = 1; i <= k; i++) {
        int x; cin >> x;
        chk[x] = 1;
    }
    dfs(1, 0);
    dfs2(1, 0);
    L[1] = f[1][0];
    dfs3(1, 0, 0);
    ans[1] <<= 1;
    dfs4(1, 0);
    for(int i = 1; i <= n; i++) ans[i] -= L[i];
    for(int i = 1; i <= n; i++) cout << ans[i] << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n >> k) run();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/heyuhhh/p/12287399.html