noi.ac NOI挑战营模拟赛1-5

注:因为博主是个每次考试都爆零垫底的菜鸡,所以此篇博客很有可能咕咕咕

(指只贴AC代码不写题解的......如果我真的不会做的话,就不能怪我了qwqwq)


Day1

T1 swap

  • 23pts 从一个状态开始爆搜,然后我们哈希一下状态,保证一个状态只被访问一次。时间复杂度\(O(n!n)\),感觉复杂度过55分没问题,但是到后面会RE.......不知为何呀QAQ
  • 55pts 枚举一下这个之后的排列,然后我们再通过判断一下每两个宽度大于n的人没有没更换相对位置来判断该结束状态的合法性(相对位置指如果原先pos_x<pos_y,之后pos_x仍然小于pos_y)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 100010
using namespace std;
int n,m,tot,ans;
int a[MAXN],pos[MAXN];
struct Line{int u,v;}line[MAXN<<1];
inline bool check()
{
	for(int i=1;i<=tot;i++)
		if(pos[line[i].u]>pos[line[i].v]) return false;
	return true;
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(a[i]+a[j]>m)
				line[++tot]=(Line){i,j};
	for(int i=1;i<=n;i++) pos[i]=i;
	do{
		if(check()==true) ans++;
	}while(next_permutation(&pos[1],&pos[n+1]));
	printf("%d\n",ans);
	return 0;
}

满分做法比较神仙,就是我们从小到大处理。对于当前最小的数,我们判断它和当前最大的数能不能交换;
如果它和最大的可以交换,那么它和当前数列里面的所有数都可以交换(意思是最后的位置有 当前序列中数的数量-->n 种)所以我们可以给答案乘上n,然后去掉这个最小数,对于剩下的序列递归计算(因为最后无论这个子序列是什么情况,最小数都可以以n种方式插入到它们中间构成答案);
如果它不能和最大的交换,那么最大的就无法和当前序列中任意一个数交换,所以它就没用了,只有在它当前位置上那一种贡献,我们删去它,递归处理子序列即可。

  • 100pts
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,m;
int a[MAXN];
vector<int>vec;
inline int solve(vector<int>x)
{
//	for(int i=0;i<x.size();i++) printf("%d ",x[i]); puts("");
	if(x.size()<=1) return 1;
	int min_pos,max_pos,minn=0x3f3f3f3f,maxx=-0x3f3f3f3f;
	for(int i=0;i<x.size();i++) 
		if(x[i]<minn)
			minn=x[i],min_pos=i;
	for(int i=0;i<x.size();i++)
		if(x[i]>maxx)
			maxx=x[i],max_pos=i;
//	printf("max_pos=%d min_pos=%d\n",max_pos,min_pos);
	if(x[min_pos]+x[max_pos]>m)
	{
		vector<int>cur1,cur2;
		cur1.clear(),cur2.clear();
		for(int i=0;i<max_pos;i++) cur1.push_back(x[i]);
		for(int i=max_pos+1;i<x.size();i++) cur2.push_back(x[i]);
		int cur_ans1=solve(cur1);
		int cur_ans2=solve(cur2);
		return 1ll*cur_ans1*cur_ans2%mod;
	}
	vector<int>cur;
	cur.clear();
	for(int i=0;i<min_pos;i++) cur.push_back(x[i]);
	for(int i=min_pos+1;i<x.size();i++) cur.push_back(x[i]);
	return 1ll*solve(cur)*x.size()%mod;
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%d",&a[i]),vec.push_back(a[i]);
	if(n==1) {printf("1\n");return 0;}
	printf("%d\n",solve(vec));
	return 0;
}

T2 stat

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 75
#define mod 1000000007
using namespace std;
int n,k;
int a[MAXN],b[MAXN];
inline void print(int *x)
{
	for(int i=1;i<=n;i++) printf("%d ",x[i]);
	puts("");
}

namespace subtask1
{
	inline void solve()
	{
		int ans=0;
		for(int i=1;i<=n;i++) a[i]=b[i]=i;
		do
		{
			do
			{
				int cur_ans=0;
				for(int i=1;i<=n;i++) cur_ans+=max(a[i],b[i]);
				if(cur_ans>=k) ans++;
			}while(next_permutation(&b[1],&b[n+1]));
		}while(next_permutation(&a[1],&a[n+1]));
		printf("%d\n",ans);
	}
}

namespace subtask2
{
	long long ans=0;
	int tmp[MAXN],done[MAXN];
	inline void search(int x)
	{
		if(x>n)
		{
			long long sum=0;
			for(int i=1;i<=n;i++) sum+=max(tmp[i],i);
			if(sum>=k) ans++;
			return; 
		}	
		for(int i=1;i<=n;i++)
		{
			if(done[i]) continue;
			tmp[x]=i,done[i]=1;
			search(x+1);
			tmp[x]=0,done[i]=0;
		}
	}
	inline void solve()
	{
		for(int i=1;i<=n;i++) done[i]=0;
		search(1);
		for(int i=1;i<=n;i++)
			ans=1ll*ans*i%mod;
		printf("%lld\n",ans);
	}
}

namespace subtask3
{
	long long ans;
	long long f[80][80][5010];
	inline void solve()
	{
		f[0][0][0]=1;
		for(int i=1;i<=n;++i)
			for(int j=0;j<i;++j)
				for(int k=0;k<=4901;++k)
					if(f[i-1][j][k])
					{
						f[i][j+1][k+i]=(f[i][j+1][k+i]+f[i-1][j][k])%mod;
						f[i][j+2][k+2*i]=(f[i][j+2][k+2*i]+f[i-1][j][k]*(i-1-j)*(i-1-j))%mod;
						f[i][j+1][k+i]=(f[i][j+1][k+i]+2*f[i-1][j][k]*(i-1-j))%mod;
						f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;
					}
		for(int i=k;i<=4901;++i)
			ans=(ans+f[n][n][i])%mod;
		for(int i=1;i<=n;++i)
			ans=(ans*i)%mod;
		printf("%lld",ans);
	}
}

using namespace subtask1;
using namespace subtask2;
using namespace subtask3;

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce2.in","r",stdin);
	#endif
	scanf("%d%d",&n,&k);
	if(n<=5) subtask1::solve();
	else if(n<=10) subtask2::solve();
	else subtask3::solve();
	return 0;
}

T3 sequence


Day2

T1 baby

#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 550000
#define M 100005
using namespace std;
int a[N][4],b[5]={-1,0,1,0,-1},d[M],e[M],f[M],g[M],h[M],i,j,l,m,n,o[N<<2],p[N<<2],q,s[N<<3],t,z;char c[N];bool w[N][4];
inline void add(int u){while(u<=t<<1)s[u]++,u+=u&-u;}
inline void del(int u){while(u<=t<<1)s[u]--,u+=u&-u;}
inline bool cmp(int u,int v){return a[d[u]][f[u]]<a[d[v]][f[v]];}
void dfs(int u,int v)
{
	++v%=4;
	while(!w[u][v])(v+=3)%=4;
	if(a[u][v]<=t)return;
	a[u][v]=++t,o[t]=u,p[t]=v;
	dfs(u+m*b[v]+b[v+1],v);
}
inline int sum(int u)
{
	int v=0;
	while(u)v+=s[u],u-=u&-u;
	return v;
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d%d%*s",&n,&m,&q),memset(a,0x7f,sizeof a);
	for(i=1;i<=n;i++)
	{
		for(scanf("%s",c),j=1;j<m;j++)if(c[j<<1]=='.')w[(i-1)*m+j][1]=w[(i-1)*m+j+1][3]=true;
		for(scanf("%s",c+1),j=1;j<=m;j++)if(c[j<<1]=='.')w[(i-1)*m+j][2]=w[i*m+j][0]=true;
	}
	for(i=0;i<q;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y),d[i]=(x-1)*m+y;
		scanf("%d%d",&x,&y),e[i]=(x-1)*m+y;
		scanf("%s",c),g[i]=i;
		if(*c=='U')f[i]=0;
		else if(*c=='R')f[i]=1;
		else if(*c=='D')f[i]=2;
		else if(*c=='L')f[i]=3;
		while(!w[d[i]][f[i]])(f[i]+=3)%=4;
	}
	for(dfs(1,0),i=1;i<=n*m;i++)add(min(min(a[i][0],a[i][1]),min(a[i][2],a[i][3])));
	for(sort(g,g+q,cmp),i=1,j=0;j<q;)
	{
		while(i<=t&&a[d[g[j]]][f[g[j]]]>i)
		del(i),a[o[i]][p[i]]+=t,add(min(min(a[o[i]][0],a[o[i]][1]),min(a[o[i]][2],a[o[i]][3]))),i++;
		while(j<q&&a[d[g[j]]][f[g[j]]]==i)
		h[g[j]]=sum(min(min(a[e[g[j]]][0],a[e[g[j]]][1]),min(a[e[g[j]]][2],a[e[g[j]]][3]))),j++;
	}
	for(i=0;i<q;i++)printf("%d\n",h[i]);
	return 0;
}

T2 Bike

T3 Boom


Day3

T1 sequence

神仙乱搞qwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 100010
using namespace std;
int n,m,q,tot,K,base,mod;
int a[MAXN],rt[MAXN];
bool done[MAXN];
struct Node{int v,ls,rs;}t[MAXN<<5];
struct Node2{int r_pos,hash;};
vector<int>pos[MAXN];//pos[a]表示a值的位置
inline void insert(int &x,int f,int l,int r,int k)
{
    x=++tot;
    t[x]=t[f],t[x].v++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid) insert(t[x].ls,t[f].ls,l,mid,k);
    else insert(t[x].rs,t[f].rs,mid+1,r,k);
}
inline int query(int x,int l,int r,int k)
{
    if(k>t[x].v||k==0) return -1;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(k<=t[t[x].ls].v) return query(t[x].ls,l,mid,k);
    else return query(t[x].rs,mid+1,r,k-t[t[x].ls].v);
}
inline void solve(vector<Node2>&x)
{
    for(int now=1;now<=n;now++)
    {
        vector<Node2>nxt;
        int minn=query(rt[x[0].r_pos+1],1,MAXN-10,now);
        // cout<<"minn="<<minn<<endl;
        if(minn==-1) return;
        int st=0;
        for(st=pos[minn].size()-1;st>=0;st--)
            {if(pos[minn][st]<=x[0].r_pos) break;}
        // cout<<"st="<<st<<endl;
        if(st+1==(int)pos[minn].size()) continue;
        for(int i=st+1;i<pos[minn].size();i++)//枚举之后能接哪些位置
        {
            for(int j=0;j<x.size()&&x[j].r_pos<pos[minn][i];j++)//枚举前面从哪个位置来接新数
            {
                int hash=(1ll*x[j].hash*base+minn)%mod;
                printf("%d\n",hash);
                // printf("K=%d\n",K);
                K--;
                if(K<=0) return;
                nxt.push_back((Node2){pos[minn][i],hash});
            }
            if(K<=0) return;
        }
        // for(int i=0;i<nxt.size();i++) cout<<nxt[i].r_pos<<" "; cout<<endl;
        solve(nxt);
        if(K<=0) return;
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d%d",&n,&K,&base,&mod);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),pos[a[i]].push_back(i);
    for(int i=n;i>=0;i--) 
    {
        if(done[a[i]]==0) 
            done[a[i]]=1,insert(rt[i],rt[i+1],1,MAXN-10,a[i]);
        else rt[i]=rt[i+1];
    }
    // for(int i=1;i<=n;i++) printf("rt[%d]=%d\n",i,rt[i]); 
    vector<Node2>cur;
    cur.push_back((Node2){0,0});
    solve(cur);
    return 0;
}

T2 game

这份代码是用emacs写的......所以缩进锅了qwqwq

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 300010
#define mod 1000000007
using namespace std;
int n,A,B,ans1,ans2,t;
int ans[MAXN],ffa[MAXN],b[MAXN],g[MAXN],c[MAXN];
int head[MAXN],dis[MAXN],fa[MAXN],pref[MAXN],suf[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline bool cmp(int x,int y){return ans[x]>ans[y];}
inline void add(int from,int to)
{
    edge[++t].nxt=head[from],edge[t].to=to;
    head[from]=t;
}
inline void dfs1(int x,int pre,int ban)
{
    ans[x]=0;
    for(int i=head[x];i;i=edge[i].nxt)
    {
	int v=edge[i].to;
	if(v==pre||v==ban) continue;
	dfs1(v,x,ban);
    }
    int cur=0;
    for(int i=head[x];i;i=edge[i].nxt)
    {
	int v=edge[i].to;
	if(v==pre||v==ban) continue;
	b[++cur]=v;
    }
    sort(&b[1],&b[cur+1],cmp);
    for(int i=1;i<=cur;i++) ans[x]=max(ans[x],ans[b[i]]+i);
}
inline void dfs2(int x,int pre)
{
    int t=0;
    if(pre) ans[0]=g[x],b[++t]=0;
    for(int i=head[x];i;i=edge[i].nxt)
    {
	int v=edge[i].to;
	if(v==pre) continue;
	b[++t]=v;
    }
    sort(&b[1],&b[t+1],cmp);
    pref[0]=suf[t+1]=0;
    for(int i=1;i<=t;i++) pref[i]=max(pref[i-1],ans[b[i]]+i);
    ans1=min(ans1,pref[t]);
    for(int i=t;i;i--) suf[i]=max(suf[i+1],ans[b[i]]+i-1);
    for(int i=1;i<=t;i++)
	if(b[i])
	    g[b[i]]=max(pref[i-1],suf[i+1]);
    for(int i=head[x];i;i=edge[i].nxt)
    {
	int v=edge[i].to;
	if(v!=pre)
	    dfs2(v,x);
    }
}
inline void dfs3(int x,int pre)
{
    for(int i=head[x];i;i=edge[i].nxt)
    {
	int v=edge[i].to;
	if(v==pre) continue;
	ffa[v]=x;
	dfs3(v,x);
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<n;i++)
    {
	int x,y;
	scanf("%d%d",&x,&y);
	add(x,y),add(y,x);
    }
    dfs1(1,0,0);
    ans1=n-1;
    dfs2(1,0);
    printf("%d\n",ans1);
    
    dfs3(A,0);
    int now=B,top=0;
    while(now) c[++top]=now,now=ffa[now];
    int l=1,r=top-1;
    ans2=n-1;
    while(l<=r)
    {
	int mid=(l+r)>>1;
	dfs1(A,0,c[mid]);
	dfs1(B,0,c[mid+1]);
	ans2=min(ans2,max(ans[A],ans[B]));
	if(ans[A]>ans[B]) l=mid+1;
	else r=mid-1;
    }
    printf("%d\n",ans2);
    return 0;
}


T3 tree

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,m;
int f[MAXN][11],fa[MAXN],st[MAXN];
inline int fpow(int x,int y)
{
    int cur_ans=1;
    while(y)
    {
        if(y&1) cur_ans=1ll*cur_ans*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return cur_ans;
}
inline void dp(int x,int y)
{
    for(int i=10;i;i--)
        for(int j=1;j<i;j++)
            f[x][i]=(f[x][i]+1ll*f[x][j]*f[y][i-j]%mod)%mod;
}
inline void dp2(int x,int y)
{
    for(int i=1;i<=10;i++)
        for(int j=1;j<i;j++)
            f[x][i]=(f[x][i]-1ll*f[x][j]*f[y][i-j]%mod)%mod;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    freopen("ce.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&f[i][1]);
    for(int i=2;i<=n;i++) scanf("%d",&fa[i]);
    for(int i=n;i>1;i--) dp(fa[i],i);
    for(int p=1;p<=m;p++)
    {
        int op,k,s,t,top;
        scanf("%d%d%d",&op,&k,&s);
        if(op==1)
        {
            for(int i=1;i<=10;i++) f[0][i]=0;
            for(t=k,top=0;t&&top<10;t=fa[t]) st[++top]=t;
            while(t=st[top--])
            {
                for(int i=1;i<=10;i++) 
                    f[n+1][i]=f[0][i],f[0][i]=f[t][i];
                dp(0,n+1);
                if(top) dp2(0,st[top]);
            }
            printf("%d\n",(f[0][s]+mod)%mod);
        }
        else
        {
            for(t=k,top=0;t&&top<10;t=fa[t]) st[++top]=t;
            for(int i=top-1;i;i--) dp2(st[i+1],st[i]);
            int cur_ans=1ll*fpow(f[k][1],mod-2)*s%mod;
            for(int i=1;i<=10;i++) 
                f[k][i]=1ll*f[k][i]*cur_ans%mod;
            for(int i=1;i<top;i++)
                dp(st[i+1],st[i]);
        }
    }
    return 0;
}


Day4

T1 tree

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 3010
using namespace std;
int n,q,k,t,ans=0x3f3f3f3f;
int dp[MAXN][MAXN][3],siz[MAXN],head[MAXN];
struct Edge{int nxt,to,dis;}edge[MAXN<<1];
inline void add(int from,int to,int dis)
{
	edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis;
	head[from]=t;
}
inline void solve(int x,int pre)
{
	siz[x]=1;
	dp[x][1][0]=dp[x][1][1]=dp[x][1][2]=0;
	dp[x][0][0]=dp[x][0][1]=dp[x][0][2]=0;
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		solve(v,x);
//		printf("x=%d v=%d\n",siz[x],siz[v]);
		for(int j=min(k,siz[x]+siz[v]);j>=2;j--)
		{
			for(int j2=max(1,j-siz[x]);j2<=min(j,siz[v]);j2++)//v_size
			{
				int j1=j-j2;//x_size
//				cout<<j2<<" "<<j2<<endl;
				dp[x][j][0]=min(dp[x][j][0],dp[x][j1][0]+dp[v][j2][0]+edge[i].dis*2);
				dp[x][j][1]=min(dp[x][j][1],dp[x][j1][0]+dp[v][j2][1]+edge[i].dis);
				dp[x][j][1]=min(dp[x][j][1],dp[x][j1][1]+dp[v][j2][0]+edge[i].dis*2);
				dp[x][j][2]=min(dp[x][j][2],dp[x][j1][1]+dp[v][j2][1]+edge[i].dis);
				dp[x][j][2]=min(dp[x][j][2],dp[x][j1][2]+dp[v][j2][0]+edge[i].dis*2);
				dp[x][j][2]=min(dp[x][j][2],dp[x][j1][0]+dp[v][j2][2]+edge[i].dis*2);
			}
		}
		siz[x]+=siz[v];
	}
	ans=min(ans,dp[x][k][2]);
//	printf("x=%d %d\n",x,ans);
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d",&n,&k);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w),add(v,u,w);
	}
	memset(dp,0x3f,sizeof(dp));
	solve(1,0);
	printf("%d\n",ans);
	return 0;
}

T2

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 10000000
#define mod 998244353
using namespace std;
int n,k,T;
int inv[MAXN+10],ff[MAXN+10],fn[MAXN+10],F[MAXN+10];
inline int fpow(int x,int y)
{
    int cur_ans=1;
    while(y)
    {
        if(y&1) cur_ans=1ll*cur_ans*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&k,&T);
    if(T==1) 
    {
        printf("1\n");
        return 0;
    }
    fn[0]=1;
    for(int i=1;i<=MAXN;i++) fn[i]=1ll*fn[i-1]*i%mod;
    inv[MAXN]=fpow(fn[MAXN],mod-2);
    for(int i=MAXN-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
    for(int i=1;i<=MAXN;i++) ff[i]=1ll*inv[i]*fn[i-1]%mod;
    int cur_ans=1;
    int cur=fpow(T-1,mod-2);
    F[0]=1ll*T*(mod-cur)%mod*(1-fpow(T,n)+mod)%mod;
    for(int i=1;i<=k;i++)
    {
        cur_ans=1ll*cur_ans*(n-i+1)%mod*ff[i]%mod;
        F[i]=(1ll*F[i-1]-1ll*T*cur_ans%mod+mod)%mod;
        F[i]=1ll*F[i]*cur%mod;
    }
    cur_ans=fpow(cur_ans,mod-2);
    printf("%lld\n",1ll*cur_ans*F[k-1]%mod);
    return 0;
}

T3

这个题的快读板子感觉挺好qwqwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define MAXN 1000010
using namespace std;
namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int qr;
	// getchar
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	// print the remaining part
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	// putchar
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	// input a integer
	template <class I>
	inline void gi (I &x) {
		for (c = gc(); c < '0' || c > '9'; c = gc());
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
	}
	// print a integer
	template <class I>
	inline void print (I &x) {
		if (!x) putc ('0');
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
}
using io :: gi;
using io :: putc;
using io :: print;
int n,Q;
int a[MAXN],p[MAXN],pos[MAXN],ans[MAXN],head[MAXN];
struct Node{int l,d,id,nxt;}q[MAXN];
inline void insert(int &x,int k)
{
    for(int i=30;i>=0;i--)
    {
        if(x&(1<<i)) 
        {
            if(!p[i]) {p[i]=x,pos[i]=k;return;}
            if(k>pos[i]) swap(k,pos[i]),swap(p[i],x);
            x^=p[i];
        }
    }
}
inline int query(int cur_ans,int l)
{
    for(int i=30;i>=0;i--)
        if(l<=pos[i]&&(cur_ans^p[i])>cur_ans) 
			cur_ans=cur_ans^p[i];
    return cur_ans;
}
int main()
{
    gi(n);
    for(int i=1;i<=n;i++) gi(a[i]);
    gi(Q);
    for(int i=1;i<=Q;++i)
	{
		int l,r,d;
		gi(l),gi(r),gi(d); 
		q[i]=(Node){l,d,i,head[r]};
		head[r]=i;
	}
	for(int i=1;i<=n;++i)
	{
		insert(a[i],i);
//		for(int i=0;i<=10;i++) printf("p[%d]=%d\n",i,p[i]);
		for(int j=head[i];j;j=q[j].nxt) 
			ans[q[j].id]=query(q[j].d,q[j].l);
	}
	for(int i=1;i<=Q;++i) print(ans[i]),putc('\n');
	io::flush();
    return 0;
}


Day5

T1 tree

T2 permutation

有限制位置的错排问题。

  • 10pts 枚举排列,然后判断是否是对的。时间复杂度\(O(n!n)\)
  • 100pts 我们考虑容斥。
    我们把已经看到值的位置直接忽略,之后就不放这个位置了,如果没有错排的限制,显然结果是\((n-k)!\)的。
    但是这样有一部分是错的对吧,错的就是比如1放到了1这种情况,我们去掉这种一个数放错的情况,就是减去\(C_{m}^1(n-k-1)!\)
    但是这样子就减多了,比如说1,2放到了1,2这种两个数放错的情况,所以要加上\(C_{m}^2(n-k-2)!\)
    .......然后以此类推,就是答案了.
    其中注意一下,如果这个数开始已经被放过了,那么我们也不需要管它.
    所以m的数量是自己原先既没有摆放位置,它对应的位置也没有数的个数.

(考场忘了最后(ans+mod)%mod)了,炸成了40.......
AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define MAXN 1000010
#define mod 998244353
using namespace std;
int n;
int p[MAXN];
namespace subtask1 //10pts
{
	int ans,cnt;
	int done[MAXN],cur[MAXN];
	inline void search(int x)
	{
		if(x>n)
		{
//			for(int i=1;i<=n;i++) printf("%d ",cur[i]); puts("");
			ans++;
			return;
		}
		if(p[x]){cur[++cnt]=p[x];search(x+1);cnt--;return;}
		for(int i=1;i<=n;i++)
		{
			if(done[i]||i==x) continue;
			done[i]=1;cur[++cnt]=i;
			search(x+1);
			done[i]=0;cnt--;
		}
	}
	inline void solve()
	{
		for(int i=1;i<=n;i++) if(p[i]) done[p[i]]=1;
		search(1);
		printf("%d\n",ans);
	}
}
namespace subtask2
{
	int fn[MAXN],inv[MAXN],f[MAXN],done[MAXN];
	inline int fpow(int x,int y)
	{
		int cur_ans=1;
		while(y)
		{
			if(y&1) cur_ans=1ll*cur_ans*x%mod;
			x=1ll*x*x%mod;
			y>>=1;
		}
		return cur_ans;
	}
	inline void init()
	{
		fn[0]=1;
		for(int i=1;i<=MAXN-10;i++) fn[i]=1ll*fn[i-1]*i%mod;
		inv[MAXN-10]=fpow(fn[MAXN-10],mod-2);
		for(int i=MAXN-10-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
//		for(int i=0;i<5;i++) printf("fn[%d]=%d\n",i,fn[i]);
//		for(int i=0;i<5;i++) printf("inv[%d]=%d\n",i,inv[i]);
	}
	inline int C(int x,int y)
	{
		if(y==0||x==y) return 1;
		if(y>x) return 0;
		return 1ll*fn[x]*inv[y]%mod*inv[x-y]%mod; 
	}
	inline void solve()
	{
		init();
		int m=0,ans=0,g=1,k=0;
		for(int i=1;i<=n;i++) 
		{
			if(p[i]) 
				k++,done[p[i]]=1;
		}
		for(int i=1;i<=n;i++)
			if(done[i]==0&&p[i]==0) m++;
		for(int i=0;i<=m;i++)
		{
//			cout<<fn[n-k-1]<<" "<<C(m,i)<<endl;
			ans=(ans+1ll*g*fn[n-k-i]%mod*C(m,i))%mod;
			g*=-1;
//			printf("i=%d ans=%d\n",i,ans);
		}
		printf("%d\n",(ans+mod)%mod);
	}
}
using namespace subtask1;
using namespace subtask2;
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
	if(n<=10) subtask1::solve();
	else subtask2::solve();
	return 0;
}

T3 color

  • 20pts 暴力枚举每条边的状态,然后判断即可。时间复杂度\(O(n^2 2^n)\)
  • 40(=20+20)pts 一条链的状态,显然每个点的答案等于\(i*(n-i+1)\)
  • 60(=20+40)pts 我们设\(dp[i]\)表示以i为根的子树的答案,那么我们枚举一下每个点作为根,就能算出来答案了。时间复杂度\(O(n^2)\)
  • 100pts 我们加上换根DP即可把枚举根的那个n优化掉。(但是注意去除影响的时候不能直接除逆元,因为这道题累加答案的操作是乘法,如果乘上了一个0的逆元就GG了--->会挂成70分)时间复杂度\(O(n)\)
    AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,t;
int fa[MAXN],dp[MAXN],head[MAXN];
int up[MAXN],pref[MAXN],suf[MAXN],b[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
vector<int>e[MAXN];
inline void add(int from,int to)
{
	edge[++t].nxt=head[from],edge[t].to=to;
	head[from]=t;
}
inline int fpow(int x,int y)
{
	int cur_ans=1;
	while(y)
	{
		if(y&1) cur_ans=1ll*cur_ans*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return cur_ans;
}
inline void init(int x,int pre)
{
	dp[x]=1;
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		init(v,x);
		dp[x]=1ll*dp[x]*(dp[v]+1)%mod;
//		dp[x]=(dp[x]+1ll*dp[x]*(dp[v]+1))%mod;
	}
}
inline void change_root(int x,int pre)
{
	dp[x]=1ll*dp[x]*(up[x]+1)%mod;
	int cnt=0;
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		b[++cnt]=dp[v];
	}
	pref[0]=(up[x]+1)%mod;
	suf[cnt+1]=1;
	for(int i=1;i<=cnt;i++) pref[i]=1ll*pref[i-1]*(b[i]+1)%mod;
	for(int i=cnt;i>=1;i--) suf[i]=1ll*suf[i+1]*(b[i]+1)%mod;
	cnt=0;
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		cnt++;
		up[v]=1ll*pref[cnt-1]*suf[cnt+1]%mod;
	}
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		change_root(v,x);
	}
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d",&n);
	for(int i=2;i<=n;i++) 
	{
		scanf("%d",&fa[i]);
		add(fa[i],i),add(i,fa[i]);
		e[fa[i]].push_back(i);
		e[i].push_back(fa[i]);
	}
	init(1,0);
//	for(int i=1;i<=n;i++) up[i]=1;
	change_root(1,0);
	for(int i=1;i<=n;i++) printf("%d ",dp[i]);
	return 0;
}

posted @ 2019-06-05 16:54  风浔凌  阅读(207)  评论(1编辑  收藏  举报