2020牛客多校第七场By Rynar

A.Social Distancing

思路:打表,首先当n为偶数时,可以得到答案为(nr)^2

//暴搜巨慢打表
#define sqr(x) (x)*(x)
int n,r,r1,r2,cnt,ct;
struct node{
    int x,y;
}a[N];
bool check(int x,int y){
    if (x*x+y*y<=r&&x*x+y*y>=r2)return 1;
    return 0;
}
bool check1(int x,int y){
    if (x*x+y*y<=r)return 1;
    return 0;
}
int dis(node a,node b){
    return sqr(a.x-b.x)+sqr(a.y-b.y);
}
int q[10];
int ans;
int dp[9][31];
void dfs(int n,int p){
    if (!n){
        int tot=0;
        for (int i=1;i<ct;i++)
            for (int j=i+1;j<=ct;j++)
                tot+=dis(a[q[i]],a[q[j]]);
        ans=max(ans,tot);
        return;
    }
    for (int i=p;i>=1;i--){
        q[n]=i;
        dfs(n-1,i);
    }
}
int main(){
    int T,x,y;
    for (int i=3;i<=7;i+=2){
        for (int j=1;j<=30;j++){
            r=sqr(j);
            r2=max(sqr(j)-12,0);
            if (i==7)r2=max(sqr(j)-11,0);
            cnt=0;
            for (int k=-j;k<=j;k++)
                for (int p=-j;p<=j;p++)
                    if (check(k,p)){
                        a[++cnt].x=k,a[cnt].y=p;
                    }
            ct=i;ans=0;
            dfs(i,cnt);
            dp[i][j]=ans;
            //printf("%d %d %d\n",i,j,ans);
        }
    }
    for (int i=2;i<=8;i+=2){
        for (int j=1;j<=30;j++){
            dp[i][j]=sqr(i*j);
        }
    }
    printf("{");
    for (int i=0;i<=8;i++){
        printf("{");
        for (int j=0;j<=30;j++){
            printf("%d",dp[i][j]);
            if (j!=30)printf(",");
        }
        if (i!=8)printf("},\n");
    }
    printf("}};\n");
    return 0;
}

B.Mask Allocation

const int N=1e6+10;
const int mod=1e9+7;
int n,m,k;
int main(){
    int T,x,y;
    scanf("%d",&T);
    while (T--){
        scanf("%d%d",&n,&m);
        if (n>m)swap(n,m);
        queue<int>q;
        while (n!=0&&m!=0){
            for (int i=1;i<=m/n*n;i++){
                q.push(n);
            }
            m=m%n;
            swap(n,m);
        }
        printf("%d\n",q.size());
        while (!q.empty()){
            printf("%d ",q.front());
            q.pop();
        }
        puts("");
    }
    return 0;
}

C.A National Pandemic

思路:树链剖分

typedef long long ll;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
#define int ll
int n,m,k;
int si[N],dep[N],fa[N],son[N];
int id[N],top[N],cnt=0;//si:子树大小,dep:深度,fa:父亲,son:重儿子,top:重链的父亲
int head[N],step=0;
int res=0;
struct edge{
    int to,n;
}e[N<<2];
void add(int x,int y){
    e[step].to=y;
    e[step].n=head[x];
    head[x]=step++;
}
void dfs1(int x,int ff,int depth){//处理dep,si,fa,son 
    dep[x]=depth;
    si[x]=1;
    fa[x]=ff;
    int mx=-1;
    for (int i=head[x];~i;i=e[i].n){
        int v=e[i].to;
        if (v==ff)continue;
        dfs1(v,x,depth+1);
        si[x]+=si[v];
        if (si[v]>mx)mx=si[v],son[x]=v;
    }
}
void dfs2(int x,int topf){//x当前节点,topf当前链的最顶端的节点 
    id[x]=++cnt;//标记每个点的新编号
    top[x]=topf;
    if(!son[x])return;//如果没有儿子则返回 
    dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理 
    for(int i=head[x];~i;i=e[i].n){
        int v=e[i].to;
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
struct node{
    int val,lazy;
    int l,r;
}tr[N<<2];
void pushup(int rt){
    tr[rt].val=tr[rt<<1].val+tr[rt<<1|1].val;
}
void putdown(int rt){
    if(tr[rt].lazy){
        tr[rt<<1].lazy+=tr[rt].lazy;
        tr[rt<<1].val+=(tr[rt<<1].r-tr[rt<<1].l+1)*tr[rt].lazy;
        tr[rt<<1|1].lazy+=tr[rt].lazy;
        tr[rt<<1|1].val+=(tr[rt<<1|1].r-tr[rt<<1|1].l+1)*tr[rt].lazy;
        tr[rt].lazy=0;
    }
}
void build(int l,int r,int rt){
    tr[rt].l=l;
    tr[rt].r=r;
    tr[rt].lazy=0;
    if (l==r){
        tr[rt].val=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void update(int l,int r,int add,int rt){
    if (l<=tr[rt].l&&r>=tr[rt].r){
        tr[rt].lazy+=add;
        tr[rt].val+=(tr[rt].r-tr[rt].l+1)*add;
        return;
    }
    putdown(rt);
    if(l<=tr[rt<<1].r)
        update(l,r,add,rt<<1);
    if(r>=tr[rt<<1|1].l)
        update(l,r,add,rt<<1|1);
    pushup(rt);
}
int query(int l,int r,int rt){
    if(l==tr[rt].l&&r==tr[rt].r)
        return tr[rt].val;
    putdown(rt);
    if(l>=tr[rt<<1|1].l)
        return query(l,r,rt<<1|1);
    else if(r<=tr[rt<<1].r)
        return query(l,r,rt<<1);
    else
        return query(l,tr[rt<<1].r,rt<<1)+query(tr[rt<<1|1].l,r,rt<<1|1);
}
void updateRange(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(id[top[x]],id[x],k,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(id[x],id[y],k,1);
}
int qRange(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){ 
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        res=query(id[top[x]],id[x],1);
        ans+=res;
        x=fa[top[x]];
    }
    //在同一链上时 
    if(dep[x]>dep[y])swap(x,y);
    res=query(id[x],id[y],1);
    ans+=res;
    return ans;
}
int ad[N],ans1,num;
signed main(){
    int T,x,y;
    scanf("%lld",&T);
    while (T--){
        num=ans1=step=cnt=0;
        memset(head,-1,sizeof head);
        memset(ad,0,sizeof ad);
        memset(son,0,sizeof son);
        scanf("%lld%lld",&n,&m);
        for (int i=1;i<n;i++){
            scanf("%lld%lld",&x,&y);
            add(x,y);add(y,x);
        }
        dfs1(1,0,1);//把1当成根
        dfs2(1,1);
        build(1,n,1);
        while(m--){
            int c,x,y,z;
            scanf("%lld",&c);
            if(c==1){
                scanf("%lld%lld",&x,&y);
                num++;
                ans1+=y-dep[x];
                updateRange(1,x,2);
            }
            else if(c==2){ 
                scanf("%lld",&x);
                int v=ans1-num*dep[x]+qRange(1,x);
                if(v>ad[x]) ad[x]=v;
            }
            else{//询问x的子树权值和 
                scanf("%lld",&x);
                printf("%lld\n",ans1-num*dep[x]+qRange(1,x)-ad[x]);
            }
        }
    }
    return 0;
}

D.Fake News

int main(){
    int T,n;
    scanf("%d",&T);
    while (T--){
        scanf("%lld",&n);
        if (n==1||n==24)puts("Fake news!");
        else puts("Nobody knows it better than me!");
    }
    return 0;
}

E.NeoMole Synthesis

F.Tokens on the Tree

G.Topo Counting

H.Dividing

typedef long long ll;
const int mod=1e9+7;
int main(){
    ll n,k;
    scanf("%lld%lld",&n,&k);
    ll ans=0;
    for(ll l=1,r;l<=min(n,k);l=r+1){
        r=min(n/(n/l),min(n,k));
        ans+=(r-l+1)*(n/l);
    }
    for(ll l=1,r;l<=min(n-1,k);l=r+1){
        r=min((n-1)/((n-1)/l),min(n-1,k));
        ans+=(r-l+1)*((n-1)/l);
    }
    printf("%lld\n",((ans-(n-1)+k-1)%mod+mod)%mod);
    return 0;
}

I.Valuable Forests

思路:由Cayley公式(可由prufer序列证明),n个点的带标号树个数为n^(n-2)
一个森林内部节点的度数平方和等于2*(长度为2的路径数+长度为3的路径数)//以下没用到
证明:首先度数平方和必然是偶数,因为奇数平方仍然是奇数,不改变原来奇偶性,度数和为2*(n-1)为偶数,度数平方和仍然是偶数
若一个节点,他的度数为k(有k个相邻点),则度数平方为k^2,他在3点中间可能数为kC2=k*(k-1)/2,其为两点中一点的可能数为kC1=k
由于长度为2的路径具有对称性,对于其相邻的点来说也有此边的计数,要/2,所以一个点 为3点中间 和 为两点中一点 所带来的收益为k*(k-1)/2+k/2=k^2/2
所以所有点的度数平方和为2*(长度为2的路径数+长度为3的路径数)

const int N=5000+10;
typedef long long ll;
int mod;
ll C[N][N],F[N][N];
ll f[N],g[N],h[N],dp[N];
void get_C(int maxn){
    C[0][0]=1;
    for(int i=1;i<=maxn;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    }
}
int main(){
    int T,n;
    scanf("%d %d",&T,&mod);
    get_C(N-1);
    F[0][0]=1;
    for(int i=1;i<N;i++){//F[i][j]为i^j
        F[i][0]=1;
        for(int j=1;j<N;j++) F[i][j]=F[i][j-1]*i%mod;
    }
    f[0]=f[1]=1;g[0]=g[1]=1;
    for (int i=2;i<N;i++){//f[i]为i^(i-2)表示n点构成的树的总可能数
        f[i]=F[i][i-2];
    }
    for(int i=2;i<N;i++){//g[i]表示i个点构成的森林的总数
        for(int j=0;j<i;j++)
            g[i]=(g[i]+C[i-1][j]*f[j+1]%mod*g[i-1-j])%mod;
    }
    h[0]=h[1]=0;
    for(int i=2;i<N;i++){//h[i]表示n点构成的所有树的度数平方和
        for(int j=1;j<i;j++){
            h[i]=(h[i]+j*j*C[i-2][j-1]%mod*F[i-1][i-j-1])%mod;
            //prufer序列从i-2个位置中选j-1个位置放p,其他位置放其他的,由于prufer序列性质,度数为(个数+1),因为p可以取1-i,最后*i
        }
        h[i]=h[i]*i%mod;
    }
    dp[0]=dp[1]=0;
    for(int i=2;i<N;i++){//dp[i]表示n点构成的所有森林的度数平方和
        for(int j=0;j<i;j++){
            dp[i]=(dp[i]+(g[i-j-1]*h[j+1]+dp[i-j-1]*f[j+1])%mod*C[i-1][j])%mod;
        }
    }
    while(T--){
        scanf("%d",&n);
        printf("%d\n",dp[n]);
    }
}

J.Pointer Analysis

posted @ 2020-08-01 19:59  Rynar  阅读(307)  评论(0)    收藏  举报