• 牛客某天比赛的简要题解+思路


    T1

    对于长度>=2的环直接后手胜利,因为只要一直对角线后手就能把先手给活活玩死

    如果有长度1的环,先手者可以给其染色,这样就自己变成后手了,所以两边一定是疯狂涂1抢后手,记录下这些环的总数是奇数就先手赢,偶数后手赢。

    T2

    树上容斥计数。

    第一个问维护下k阶子树的size以及k阶祖先,加加减减无脑容斥算一下就行了,复杂度O(nk)

    第二个问维护下k阶子树的乘积和,然后发现除了自己以及自己的祖先,所有的贡献都可以直接用这个乘积和算,把加加减减换成乘乘除除,改动目测不大,需要逆元。

    对于不能这样算的点,由于只有k+1个不能这样算的点,这些点单独统计下贡献,最后乘到答案里面去就行了,目测O(nk)或者O(nk^2),都可以接受。

    update:是O(nk)的(不算逆元的话

    代码如下:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #define int long long int
     
    using namespace std;
     
    inline int read() {
        int x=0,f=1;
        char cr=getchar();
        while (cr>'9' || cr<'0') {
            if (cr=='-') f=-1;
            cr=getchar();
        }
        while (cr>='0' && cr<='9') {
            x=(x<<3)+(x<<1)+cr-'0';
            cr=getchar();
        }
        return x*f;
    }
     
    const int maxn=100005;
     
    const int mod=1e9+7;
     
    struct edge{
        int to,next;
    }e[maxn<<1];
     
    int cnt,head[maxn];
     
    inline void add(int u,int v) {
        e[++cnt].to=v;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
     
    int fa[maxn][15],size[maxn][15];
     
    int n,k;
     
    inline void dfs(int now,int fan) {
        for (int i=0;i<=k;i++) size[now][i]=1;
        fa[now][0]=now,fa[now][1]=fan;
        for (int i=2;i<=k;i++) fa[now][i]=fa[fa[now][i-1]][1];
        for (int i=head[now];i;i=e[i].next) {
            int to=e[i].to;
            if (to==fan) continue;
            dfs(to,now);
            for (int i=1;i<=k;i++) size[now][i]+=size[to][i-1];
        }
    }
     
    inline int query(int now) {
        if (now==1) return size[now][k];
        int ret=size[now][k];
        for (int i=1;i<=k;i++) {
            if (fa[now][i]==0) break;
            ret+=size[fa[now][i]][k-i];
    		if (k-i-1>=0) ret-=size[fa[now][i-1]][k-i-1];
        }
        return ret;
    }
     
    int mul[maxn][15];//子树到根的乘积和
     
    inline void dfs_lunatic(int now,int fan) {
        for (int i=0;i<=k;i++) mul[now][i]=size[now][i];
        for (int i=head[now];i;i=e[i].next) {
            int to=e[i].to;
            if (to==fan) continue;
            dfs_lunatic(to,now);
            for (int i=1;i<=k;i++) mul[now][i]*=mul[to][i-1],mul[now][i]%=mod;
        }
    }
    
    inline int power(int a,int b) {
    	int ans=1;
    	while (b) {
    		if (b&1) ans*=a,ans%=mod;
    		b>>=1;
    		a*=a,a%=mod;
    	}
    	return ans;
    }
    
    inline int inv(int now) {
    	return power(now,mod-2);
    }
    
    inline int query_lunatic(int now) {
    	if (now==1) return mul[now][k];
    	int ret=mul[now][k]*inv(size[now][k])%mod;
    	int contri=1;
    	for (int i=1;i<=k;i++) {
    		if (fa[now][i]==0) break;
    		ret*=mul[fa[now][i]][k-i],ret%=mod;
    		if (k-i-1>=0) ret*=inv(mul[fa[now][i-1]][k-i-1]),ret%=mod;
    		ret*=inv(size[fa[now][i]][k-i]),ret%=mod;
    	}
    	int size_now=0;
    	for (int i=k;i>=0;i--) {
    		if (fa[now][i]==0) continue;
    		size_now+=size[fa[now][i]][k-i];
    		if (k-i-1>=0) size_now-=size[fa[now][i-1]][k-i-1];
    		contri*=size_now;
    		contri%=mod;
    	}
    	return ret*contri%mod;
    }
    
    signed main() {
        n=read(),k=read();
        for (int i=1;i<n;i++) {
            int x=read(),y=read();
            add(x,y),add(y,x);
        }
        dfs(1,0);
        for (int i=1;i<=n;i++) printf("%lld ",query(i));
        printf("
    ");
        dfs_lunatic(1,0);
    	for (int i=1;i<=n;i++) printf("%lld ",query_lunatic(i));
        printf("
    ");
        return 0;
    }
    

      

    T3

    hzhT2连边法之后 观察到基环树=全覆盖,树=必定有一个无法覆盖。

    也就是说如果你的顺子在树上就扑街了。

    对于每颗树,找出其最小值和最大值当成区间,如果你的询问包含了一个树的区间,那就炸了。

    个人觉得答案还是可以双指针统计覆盖,也就是维护起点,每一次往前推起点的时候,接着推终点。可能要数据结构来维护?不太清楚。

    这题放了二分图过,其实给个60分还是合理,放过去太扯了。但是相比T2的80分暴力来说这个还没那么扯。

    这个题目我觉得出的挺好,就是数据SB了点。

    链接:https://ac.nowcoder.com/acm/contest/1100#question

  • 相关阅读:
    php date 时间差
    array_merge 和 + 号的的区别
    apache 添加https后导致http无法访问
    php 获取url
    TP5 事务处理
    LeetCode 每日一题 (盛最多水的容器)
    LeetCode 每日一题 (字符串转换整数 (atoi))
    LeetCode 每日一题(5. 最长回文子串)
    LeetCode 每日一题 (3 无重复字符的最长子串)
    LeetCode 每日一题 (两数相加)
  • 原文地址:https://www.cnblogs.com/YoOXiii/p/11764159.html
Copyright © 2020-2023  润新知