[2018 年 3 月雅礼省选培训]Escape Machine Maze

备赛状态,十分感谢定哥特许我不考期末(否则全科爆零?)来到机房浪. LFYZ 161 Escape LFYZ 162 machine LFYZ 163 Maze

Escape

题意
一棵树,树上每个点上都有ai个人,他们和你同速一直向你奔来,问你若目的地为树上某一个点的时候,一路上能够撞见多少人.n1e5
题解
开始一直在想点分orz.事实上,我们考虑若目的地为x,那么对于y能够撞见你,只当(dis[y])/2<=dis[x].那么我们一路上做树上前缀和就可以了.
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>

using namespace std;
const int maxn = 2e5+5;
int en[maxn],nt[maxn],la[maxn],owo;
void adg(int x,int y) {
    en[++owo]=y; nt[owo] = la[x]; la[x]=owo;
}
int n;
int A[maxn];
int fa[20][maxn],dep[maxn];
void dfs1(int x,int ba) {
    fa[0][x] = ba;
    for(int i=1;i<=19;i++) fa[i][x] = fa[i-1][fa[i-1][x]];
    for(int it=la[x];it;it=nt[it]) {
        int y = en[it]; if(y==ba) continue;
        dep[y] = dep[x] + 1; dfs1(y,x);
    }
}
int ans[maxn],ad[maxn];
void dfs2(int x,int ba,int sum) {
    sum += ad[x]; ans[x] = sum;
    for(int it=la[x];it;it=nt[it]) {
        int y = en[it]; if(y==ba) continue;
        dfs2(y,x,sum);
    }
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&A[i]);
    }
    for(int i=1;i<n;i++) {
        int x,y; scanf("%d%d",&x,&y);
        adg(x,y); adg(y,x);
    }
    dfs1(1,0);
    for(int i=1;i<=n;i++) {
        int dp = (dep[i])>>1; int x = i;
        for(int s=19;s>=0;s--) if(dp>=(1<<s)) x = fa[s][x],dp-=(1<<s);
        ad[x] += A[i];
    }
    dfs2(1,0,0);
    for(int i=1;i<=n;i++) {
        printf("%d\n",ans[i]);
    }
}

Machine

题意
给你一个一一映射的函数,每次询问其与1狄利克雷卷积k次之后的函数的某一项f(x)是多少.询问次数1000,k,n 1e5
题解
肯定最后只有是x的约数才会对答案产生贡献.对于其中的某一项一定也是他的约数对他产生贡献.我们发现对于每一个质因数之间产生贡献的频率(或者说是前缀和序列,因为我们发现对于相同质因数的数从小到大排之后是一个类似高维前缀和的东西),那么我们再拆开质因数考虑那个数对于x的贡献系数C(i+k-1,i)(loj 一个人的数论) 说得很不清楚..可能代码相对比较好理解吧orz
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>

using namespace std;
const int maxn = 4e5+5;
const int mod = 998244353;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int ksm(int a,int b) {
    int ans = 1;
    for(;b;b>>=1,a=mul(a,a))
        if(b&1) ans = mul(ans,a);
    return ans;
}
int n;
int fac[maxn],inv[maxn];
int F[maxn];
int GC(int x,int y) { if(x<y) return 0; return mul(fac[x],mul(inv[y],inv[x-y]));}
int pri[maxn],cnt,mind[maxn];
bool mk[maxn];
void init(int S) {
    mk[1] = mk[0] = 1;
    for(int i=2;i<=S;i++) {
        if(!mk[i]) { pri[++cnt] = i; mind[i] = i; }
        for(int j=1;j<=cnt&&1ll*pri[j]*i<=S;j++) {
            int k = pri[j]*i; mk[k] = 1;
            mind[k] = pri[j];
            if(i%pri[j]==0) break;
        }
    }
}
int calc(int k,int x) {
    int ans = 1;
    int cc = 0; int orz = mind[x];
    while(x!=1) {
        cc = 0; while(x%orz==0) x/=orz,cc++;
        ans = mul(ans,GC(k-1+cc,cc));
        orz = mind[x];
    }
    return ans;
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&F[i]);
    }
    init(maxn-5);
    fac[0] = 1; for(int i=1;i<=maxn-5;i++) fac[i] = mul(fac[i-1],i);
    inv[maxn-5] = ksm(fac[maxn-5],mod-2);
    for(int i=maxn-6;i>=0;i--) inv[i] = mul(inv[i+1],i+1);
    int m; scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        int k,x; scanf("%d%d",&k,&x);
        if(k==0) {
            printf("%d",F[x]); continue;
        }
        int ans = 0;
        int sq = 0;
        for(int j=1;j*j<=x;j++) {
            if(x%j==0) {
                ans = add(ans,mul(calc(k,j),F[x/j]));
                if(j*j!=x) ans = add(ans,mul(calc(k,x/j),F[j]));
            }
        }
        printf("%d\n",ans);
    }
}

Maze

题意
这是一棵无限深度二叉树.给你一个初始深度1e5,保证每个点连出去的三条边,一定是三种不同颜色. 交互库函数:move(i)从当前节点走颜色i,query()询问当前深度.传给你设计函数getpath(int depth,int T)初始深度,最多询问次数T(5e4),最终move次数不超过1e6
题解
感觉看了题解好巧妙啊,,已经是第3次做到交互题,然而感觉还是觉得头绪不大... 考虑先暴力走到父亲,设该点x,然后随机走9步之后走到y,找到他们的lca z,走回z,然后若y!=z,那么可以确定下一步的父亲,若不是就是说往上一直走了9步,很赚,暴力再找一下父亲就好. 根据期望他就这样到了orz,并且卡死了询问次数和move次数orz
#include "maze.h"
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
bool vis[3];
unsigned int RD() {
    static unsigned int seed = 19260817;
    seed^=seed<<13;
    seed^=seed>>17;
    seed^=seed<<5;
    return seed;
}
int DIS;
int fr[11];
int LAS;
bool fk[3];
void TOF() {
    for(int i=0;i<3;i++) {
        if(fk[i]) continue;
        move(i);
        if(query()>DIS) move(i);
        else {
            LAS = i;
            return;
        }
    }
}
bool ZOU(int now) {
    int O = RD()%2;
    for(int i=0;i<3;i++) {
        if(fk[i]) continue;
        if(O==0) {
            if(move(i)) return 1; fr[now] = i;
            return 0;
        }
        O--;
    }
    return 0;
}
void findpath(int ddddd, int T) {
    DIS = ddddd;
    if(DIS==0) return;
    TOF(); DIS--;
    if(DIS==0) return;
    while(233) {
        fr[0] = LAS;
        for(int i=1;i<=9;i++) {
            memset(fk,0,sizeof fk);
            fk[fr[i-1]] = 1;
            if(ZOU(i)) return;
        }
        int WZ = query();
        int LCA = (WZ+DIS-9)/2;
        int delta = WZ-LCA;
        for(int i=9,d=1;d<=delta;d++,i--) {
            move(fr[i]);
        }
        DIS = LCA;
        if(delta==0) {
            memset(fk,0,sizeof fk);
            fk[fr[9]] = 1;
            LAS = fr[9];
            if(DIS==0) return;
        } else {
            memset(fk,0,sizeof fk);
            fk[fr[9-delta+1]] = 1; fk[fr[9-delta]] = 1;
            for(int i=0;i<3;i++) {
                if(!fk[i]) {
                    LAS = i;
                    if(move(i)) return;
                }
            }
            DIS--;
        }
    }
}
posted @ 2019-01-21 12:07  Newuser233  阅读(16)  评论(0)    收藏  举报