Loading

正睿 11.1 模拟赛题解

T1

毒瘤计数题,至少想假了 \(5\) 次。

不难发现,\(d\) 不管是奇数还是偶数,都有一个中心点,我们考虑如果 \(d\) 为偶数,那么中心就是一个点,否则及时一条边,不难发现中间为一条边是好做的,我们直接预处理回答询问即可。至于偶数,我们可以遍历其邻点,然后对于哪些点我们枚举所有组合方式,减去不合法的即可。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 4010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;
const int mod=1e9+7;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

struct edge{
    int from,to,next;
    inline void Init(int fr_,int to_,int ne_){
        from=fr_;to=to_;next=ne_;
    }
}li[N<<1];
int head[N],tail=1;

inline void Add(int from,int to){
    li[++tail].Init(from,to,head[from]);
    head[from]=tail;
}

int d[N][N][2],Dep[N],sum[N][N][2],Root,n,m,Tag,TwoPow[N];

inline int ksm(int a,int b,int mod){
    int res=1;while(b){if(b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;
}

inline void dfs(int k,int fa,int op){
    Dep[k]=Dep[fa]+1;d[Root][Dep[k]][op]++;
    for(int x=head[k];x;x=li[x].next){
        int to=li[x].to;
        if(Tag==x||(Tag^1)==x) continue;
        if(to==fa) continue;
        dfs(to,k,op);
    }
}

inline void Init(){
    read(n);
    for(int i=1;i<=n-1;i++){
        int from,to;read(from);read(to);
        Add(from,to);Add(to,from);
    }
    Dep[0]=-1;
    for(int i=2;i<=tail;i++){
        Tag=i;Root=i;dfs(li[i].from,0,0);dfs(li[i].to,0,1);
        sum[i][0][0]=d[i][0][0];sum[i][0][1]=d[i][0][1];
        for(int j=1;j<=n;j++){
            sum[i][j][0]=sum[i][j-1][0]+d[i][j][0];
            sum[i][j][1]=sum[i][j-1][1]+d[i][j][1];
        }
        // printf("li[%d].from=%d li[%d].to=%d\n",i,li[i].from,i,li[i].to);
        // for(int j=1;j<=n;j++){
        //     printf("d[%d][%d][0]=%d d[%d][%d][1]=%d\n",i,j,d[i][j][0],i,j,d[i][j][1]);
        // }
    }
    TwoPow[0]=1;
    for(int i=1;i<=n;i++) TwoPow[i]=1ll*TwoPow[i-1]*2%mod;
}

inline void Solve(){
    read(m);
    for(int i=1;i<=m;i++){
        int di;read(di);
        int Ans=0;
        if(di&1){
            int len=di/2;
            for(int j=2;j<=tail;j+=2){
                int n1=d[j][len][0];
                int n2=d[j][len][1];
                int m=0;
                if(len>=1) (m+=sum[j][len-1][0]+sum[j][len-1][1])%=mod;
                Ans=(Ans+1ll*(TwoPow[n1]-1)*(TwoPow[n2]-1)%mod*TwoPow[m])%mod;
            }
        }
        else{
            for(int i=1;i<=n;i++){
                int sum1=0,sum2=1;
                for(int x=head[i];x;x=li[x].next){
                    // sum1=(sum1+d[x][di/2-1][1]);
                    if(di/2>=2) sum2=(sum2+sum[x][di/2-2][1])%mod;
                }
                int now=1;
                for(int x=head[i];x;x=li[x].next){
                    // now=(now+1ll*(sum1-d[x][di/2-1][1])*d[x][di/2-1][1]%mod)%mod;
                    // now=1ll*now*(d[x][di/2-1][1]+1);
                    now=1ll*now*((TwoPow[d[x][di/2-1][1]]-1)+1)%mod;
                    (sum1+=(TwoPow[d[x][di/2-1][1]]-1))%=mod;
                }
                now--;now-=sum1;
                Ans=(Ans+1ll*now*TwoPow[sum2]%mod)%mod;
            }
        }
        printf("%d\n",(Ans%mod+mod)%mod);
    }
}

signed main(){
    freopen("my.in","r",stdin);
    freopen("my.out","w",stdout);
    Init();Solve();
    return 0;
}

T2

二分图博弈学习笔记例题 3。

链接

T3

这个题正解是用树上被增法,然而因为数据过水,所以暴力可做。据说出题人是随机建树。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 500010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
	x=0; int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	x*=f;
}

template<typename T> inline T Max(T a,T b){return a<b?b:a;}

int n,m,tot;
map<int,int> Map[N];
vector<int> v[N],col[N];
int From[N],To[N],Fa[N][32],Dep[N];

inline void Dfs(int k,int f){
	Dep[k]=Dep[f]+1;Fa[k][0]=f;
	for(int i=1;i<=30;i++) Fa[k][i]=Fa[Fa[k][i-1]][i-1];
	for(int to:v[k]){if(to==f) continue;Dfs(to,k);}
}

inline int GetLca(int a,int b){
	if(Dep[a]<Dep[b]) swap(a,b);
	for(int i=30;i>=0;i--) if(Dep[Fa[a][i]]>=Dep[b]) a=Fa[a][i];
	if(a==b) return a;
	for(int i=30;i>=0;i--) if(Fa[a][i]!=Fa[b][i]){a=Fa[a][i];b=Fa[b][i];}return Fa[a][0];
}

inline void Init(){
	read(n);read(m);
	for(int i=1;i<=m;i++){
		int from,to,w;read(from);read(to);read(w);
		if(!Map[from][to]){
			Map[from][to]=++tot;Map[to][from]=tot;
			v[from].push_back(to);v[to].push_back(from);
			From[tot]=from;To[tot]=to;
			col[tot].push_back(w);
		}
		else col[Map[from][to]].push_back(w);
	}
	Dfs(1,0);
}

inline void Solve(int a,int b){
	int Lca=GetLca(a,b);
	// printf("Lca=%d\n",Lca);
	vector<int> Road,c;Road.clear();
	int k=a;while(k!=Lca){Road.push_back(k);k=Fa[k][0];}
	Road.push_back(Lca);c.clear();
	k=b;while(k!=Lca){c.push_back(k);k=Fa[k][0];}
	for(int i=c.size()-1;i>=0;i--) Road.push_back(c[i]);
	priority_queue<pair<int,int> > q[2];
	q[0].push(make_pair(0,0));int o=0;
	// for(int i=0;i<Road.size();i++) printf("%d ",Road[i]);
	// puts("");
	for(int i=0;i<Road.size()-1;i++){
		// printf("i=%d\n",i);
		o^=1;int now=Map[Road[i]][Road[i+1]];
		while(q[o].size()) q[o].pop();
		for(int co:col[now]){
			pair<int,int> Top=q[o^1].top();
			if(co!=Top.second){q[o].push(make_pair(Top.first+1,co));}
			else{
				q[o^1].pop();
				if(q[o^1].size()){
					q[o].push(make_pair(Max(Top.first,q[o^1].top().first+1),co));
				}
				else q[o].push(make_pair(Top.first,co));
				q[o^1].push(Top);
			}
		}
	}
	printf("%d\n",Max(0,q[o].top().first-1));
}

int q;

int main(){
	// freopen("my.in","r",stdin);
	// freopen("my.out","w",stdout);
	Init();
	read(q);
	while(q--){
		int a,b;read(a);read(b);
		Solve(a,b);
	}
	return 0;
}
posted @ 2021-11-03 20:19  hyl天梦  阅读(43)  评论(0编辑  收藏  举报