• CSP-S2019题解


    D1T1

    判断每一位是否超过一半,如果超了就把后面的反过来

    注意不要把k+1

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    using namespace std;
    
    unsigned long long p[64];
    unsigned long long m;
    int n,i,j,k,l;
    
    int main()
    {
    	freopen("code.in","r",stdin);
    	freopen("code.out","w",stdout);
    	
    	p[0]=1;
    	fo(i,1,63)
    	p[i]=p[i-1]*2;
    	
    	cin>>n>>m;
    	
    	fd(i,n-1,0)
    	if (m<p[i])
    	printf("0");
    	else
    	printf("1"),m=p[i]-(m-p[i])-1;
    	printf("
    ");
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    

    D1T2

    主席树碾过

    找最后一个前缀和相同的

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    
    int tr[10500001][5]; //sonl sonr max maxid sum
    int b[500001];
    int fa[500001];
    long long ans[500001];
    int d[500001];
    int N,n,i,j,k,l,len,Find,Find2;
    long long Ans;
    char ch;
    
    void New(int t,int x)
    {
    	++len;
    	tr[len][0]=tr[tr[t][x]][0];
    	tr[len][1]=tr[tr[t][x]][1];
    	tr[len][2]=tr[tr[t][x]][2];
    	tr[len][3]=tr[tr[t][x]][3];
    	tr[len][4]=tr[tr[t][x]][4];
    	
    	tr[t][x]=len;
    }
    
    void change(int t,int l,int r,int x,int s)
    {
    	int mid=(l+r)/2;
    	
    	if (d[s]>tr[t][2])
    	{
    		tr[t][2]=d[s];
    		tr[t][3]=s;
    	}
    	
    	if (l==r)
    	{
    		++tr[t][4];
    		return;
    	}
    	
    	if (x<=mid)
    	{
    		New(t,0);
    		change(tr[t][0],l,mid,x,s);
    	}
    	else
    	{
    		New(t,1);
    		change(tr[t][1],mid+1,r,x,s);
    	}
    }
    
    void find1(int t,int l,int r,int x,int y)
    {
    	if (x>y) return;
    	
    	int mid=(l+r)/2;
    	
    	if (x<=l && r<=y)
    	{
    		if (tr[t][2]>Find)
    		Find=tr[t][2],Find2=tr[t][3];
    		
    		return;
    	}
    	
    	if (x<=mid && tr[t][0])
    	find1(tr[t][0],l,mid,x,y);
    	if (mid<y && tr[t][1])
    	find1(tr[t][1],mid+1,r,x,y);
    }
    
    int find2(int t1,int t2,int l,int r,int x)
    {
    	int mid=(l+r)/2;
    	
    	if (l==r)
    	return tr[t2][4]-tr[t1][4];
    	
    	if (x<=mid)
    	return find2(tr[t1][0],tr[t2][0],l,mid,x);
    	else
    	return find2(tr[t1][1],tr[t2][1],mid+1,r,x);
    }
    
    int main()
    {
    	freopen("brackets.in","r",stdin);
    	freopen("brackets.out","w",stdout);
    	
    	scanf("%d",&n);N=n+n+1;
    	fo(i,1,n)
    	{
    		ch=getchar();
    		while (ch!='(' && ch!=')')
    		ch=getchar();
    		
    		if (ch=='(')
    		b[i]=1;
    		else
    		b[i]=-1;
    	}
    	fo(i,2,n)
    	scanf("%d",&fa[i]);
    	
    	d[1]=1;
    	len=n;
    	
    	change(1,1,N,b[1]+(n+1),1);
    	fo(i,2,n)
    	{
    		tr[i][0]=tr[fa[i]][0];
    		tr[i][1]=tr[fa[i]][1];
    		tr[i][2]=tr[fa[i]][2];
    		tr[i][3]=tr[fa[i]][3];
    		tr[i][4]=tr[fa[i]][4];
    		
    		d[i]=d[fa[i]]+1;
    		b[i]+=b[fa[i]];
    		
    		Find=0;
    		Find2=0;
    		
    		find1(i,1,N,1,b[i]-1+(n+1));
    		
    		ans[i]=find2(Find2,i,1,N,b[i]+(n+1));
    		if (b[i]==0 && !Find2)
    		++ans[i];
    		
    		change(i,1,N,b[i]+(n+1),i);
    	}
    	fo(i,1,n)
    	{
    		ans[i]+=ans[fa[i]];
    		Ans^=ans[i]*i;
    	}
    	
    	printf("%lld
    ",Ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    

    D1T3

    枚举每个数最终到哪个点上,因为直接判边与边的关系不好搞,所以用链表维护每个点相连的边之间的关系

    关系有三种:第一条,两条边相邻,最后一条

    再建两个点表示头和尾,枚举时判断是否合法即可

    因为剩下无限制的边随便放必定合法

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    using namespace std;
    
    int a[4002][2];
    int ls[2001];
    int b[2001];
    int pre[2001][2002];
    int nxt[2001][2002];
    int ans[2001];
    int d[2001];
    int d1[2001];
    int d2[2001];
    int T,n,i,j,k,l,len,mn,tot;
    bool bz;
    
    void New(int x,int y)
    {
    	++len;
    	a[len][0]=y;
    	a[len][1]=ls[x];
    	ls[x]=len;
    }
    
    void dfs(int Fa,int Ls,int t)
    {
    	int id,i,j,k,l;
    	
    	if (t==2 && Fa==0)
    	n=n;
    	
    	if (Ls && nxt[t][Ls]==Ls && pre[t][n+1]==n+1 && (pre[t][Ls]!=0 || d[t]==1))
    	mn=min(mn,t);
    	
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		if (t==3)
    		n=n;
    		
    		id=i/2;
    		
    		if (!Ls && pre[t][id]==id && nxt[t][0]==0 && (nxt[t][id]!=n+1 || d[t]==1) || Ls && pre[t][Ls]!=id && nxt[t][Ls]==Ls && pre[t][id]==id && (pre[t][Ls]!=0 || nxt[t][id]!=n+1 || d[t]==1))
    		dfs(t,id,a[i][0]);
    	}
    }
    
    void Dfs(int Fa,int t)
    {
    	int i;
    	
    	if (t==mn)
    	{
    		bz=1;
    		return;
    	}
    	
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		++tot;
    		d1[tot]=a[i][0];
    		d2[tot]=i/2;
    		
    		Dfs(t,a[i][0]);
    		
    		if (bz)
    		return;
    		
    		--tot;
    	}
    }
    
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    	
    	scanf("%d",&T);
    	for (;T;--T)
    	{
    		memset(ls,0,sizeof(ls));
    		memset(d,0,sizeof(d));
    		len=1;
    		
    		scanf("%d",&n);
    		fo(i,1,n)
    		scanf("%d",&b[i]),++d[i];
    		fo(i,2,n)
    		{
    			scanf("%d%d",&j,&k);
    			
    			New(j,k);
    			New(k,j);
    			
    			++d[j];
    			++d[k];
    		}
    		
    		if (n==1)
    		{
    			printf("1
    ");
    			continue;
    		}
    		
    		fo(i,1,n)
    		{
    			fo(j,0,n+1)
    			pre[i][j]=nxt[i][j]=j;
    		}
    		
    		fo(i,1,n)
    		{
    			bz=tot=0;
    			mn=n+1;
    			
    			dfs(0,0,b[i]);
    			Dfs(0,b[i]);
    			
    			nxt[b[i]][0]=d2[1];
    			pre[b[i]][nxt[b[i]][d2[1]]]=0;
    			
    			if (nxt[b[i]][d2[1]]!=d2[1])
    			pre[b[i]][d2[1]]=nxt[b[i]][d2[1]]=-1;
    			
    			--d[b[i]];
    			
    			fo(j,1,tot-1)
    			{
    				k=pre[d1[j]][d2[j]];
    				l=nxt[d1[j]][d2[j+1]];
    				
    				nxt[d1[j]][k]=l;
    				pre[d1[j]][l]=k;
    				
    				if (pre[d1[j]][d2[j]]!=d2[j])
    				nxt[d1[j]][d2[j]]=pre[d1[j]][d2[j]]=-1;
    				if (nxt[d1[j]][d2[j+1]]!=d2[j+1])
    				nxt[d1[j]][d2[j+1]]=pre[d1[j]][d2[j+1]]=-1;
    				
    				--d[d1[j]];
    			}
    			
    			pre[d1[tot]][n+1]=d2[tot];
    			nxt[d1[tot]][pre[d1[tot]][d2[tot]]]=n+1;
    			
    			if (pre[d1[tot]][d2[tot]]!=d2[tot])
    			pre[d1[tot]][d2[tot]]=nxt[d1[tot]][d2[tot]]=-1;
    			
    			--d[d1[tot]];
    			
    			ans[i]=mn;
    		}
    		
    		fo(i,1,n)
    		printf("%d ",ans[i]);
    		printf("
    ");
    	}
    }
    

    D2T1

    n^3m显然,把总数和钦定的数做差即可续走一个n

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define add(a,b) a=((a)+(b))%998244353
    #define mod 998244353
    #define Mod 998244351
    using namespace std;
    
    int a[101][2001];
    long long sum[101];
    long long f[101][201];
    int n,m,i,j,k,l;
    long long ans;
    
    int main()
    {
    	freopen("meal.in","r",stdin);
    	freopen("meal.out","w",stdout);
    	
    	ans=1;
    	scanf("%d%d",&n,&m);
    	fo(i,1,n)
    	{
    		fo(j,1,m)
    		{
    			scanf("%d",&a[i][j]);
    			add(sum[i],a[i][j]);
    		}
    		ans=ans*(sum[i]+1)%mod;
    	}
    	--ans;
    	
    	fo(l,1,m)
    	{
    		memset(f,0,sizeof(f));
    		f[0][100]=1;
    		
    		fo(i,0,n-1)
    		{
    			fo(j,-i,i)
    			if (f[i][j+100])
    			{
    				add(f[i+1][j+1+100],f[i][j+100]*a[i+1][l]);
    				add(f[i+1][j-1+100],f[i][j+100]*(sum[i+1]-a[i+1][l]));
    				add(f[i+1][j+100],f[i][j+100]);
    			}
    		}
    		
    		fo(j,1,n)
    		add(ans,-f[n][j+100]);
    	}
    	
    	printf("%lld
    ",(ans+mod)%mod);
    }
    

    D2T2

    找规律,每次从后选最靠右的合法段

    处理出每个前缀的最小末段和,单调栈优化

    证明见uoj

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (register int a=b; a<=c; a++)
    #define fd(a,b,c) for (register int a=b; a>=c; a--)
    using namespace std;
    
    __int128 ans,s;
    long long a[40000001];
    long long f[40000001];
    int d[40000001];
    int P[100001];
    int L[100001];
    int R[100001];
    int n,type,i,j,k,l,h,t;
    long long x,y,z,m;
    
    void Printf(__int128 t)
    {
    	if (t)
    	{
    		Printf(t/10);
    		printf("%d",(int)(t%10));
    	}
    }
    
    int main()
    {
    	freopen("partition.in","r",stdin);
    	freopen("partition.out","w",stdout);
    	
    	scanf("%d%d",&n,&type);
    	if (!type)
    	{
    		fo(i,1,n)
    		scanf("%lld",&a[i]),a[i]+=a[i-1];
    	}
    	else
    	{
    		scanf("%lld%lld%lld%lld%lld%lld",&x,&y,&z,&a[1],&a[2],&m);
    		fo(i,1,m)
    		scanf("%d%d%d",&P[i],&L[i],&R[i]);
    		
    		fo(i,3,n)
    		a[i]=(x*a[i-1]+y*a[i-2]+z)%1073741824;
    		
    		fo(i,1,m)
    		{
    			fo(j,P[i-1]+1,P[i])
    			a[j]=a[j]%(R[i]-L[i]+1)+L[i];
    		}
    		
    		fo(i,1,n)
    		a[i]+=a[i-1];
    	}
    	
    	h=t=1;
    	d[1]=0;
    	fo(i,1,n)
    	{
    		while (h<t && f[d[h+1]]<=a[i])
    		++h;
    		
    		f[i]=a[i]-a[d[h]]+a[i];
    		while (h<=t && f[d[t]]>=f[i])
    		--t;
    		
    		d[++t]=i;
    	}
    	
    	l=n;
    	fd(i,n,1)
    	if (f[i-1]<=a[l])
    	{
    		s=a[l]-a[i-1];
    		ans+=s*s;
    		
    		l=i-1;
    	}
    	
    	Printf(ans);
    	printf("
    ");
    }
    

    D2T3

    重心性质:

    1.重心一定在重链上

    如果不在那么一定可以向重链方向移动

    2.一个点是重心当前仅当该点的重儿子size<=n/2

    若不满足则可以向重儿子方向移动,移动后必更优


    考虑计算断掉每条边的贡献,向下直接倍增找到最后一个总size-当前size<=总size/2的点,这个点&其父亲可能是重心

    向上的就边做边维护倍增数组,回溯时修改断边深度浅的点

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    
    int a[600001][2];
    int ls[300001];
    int fa[300001];
    int nx[300001][19];
    int Nx[300001][19];
    int size[300001];
    int T,n,i,j,k,l,len;
    long long ans;
    
    void New(int x,int y)
    {
    	++len;
    	a[len][0]=y;
    	a[len][1]=ls[x];
    	ls[x]=len;
    }
    
    void dfs1(int Fa,int t)
    {
    	int i,mx1=0,mx2=0;
    	
    	fa[t]=Fa;
    	
    	size[t]=1;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		dfs1(t,a[i][0]);
    		size[t]+=size[a[i][0]];
    		
    		if (size[a[i][0]]>mx1)
    		mx1=size[a[i][0]],mx2=a[i][0];
    	}
    	
    	nx[t][0]=mx2;
    	fo(i,1,18)
    	nx[t][i]=nx[nx[t][i-1]][i-1];
    }
    
    void dfs2(int Fa,int t)
    {
    	int i,j,mx1=0,mx2=0,Mx1=0,Mx2=0,Size;
    	
    	for (i=ls[t]; i; i=a[i][1])
    	{
    		if (size[a[i][0]]>mx1)
    		{
    			Mx1=mx1,Mx2=mx2;
    			mx1=size[a[i][0]],mx2=a[i][0];
    		}
    		else
    		if (size[a[i][0]]>Mx1)
    		Mx1=size[a[i][0]],Mx2=a[i][0];
    	}
    	
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		Size=size[t];
    		fa[t]=a[i][0];
    		size[t]=n-size[a[i][0]];
    		
    		if (a[i][0]==mx2)
    		{
    			if (Mx1>n-Size)
    			Nx[t][0]=Mx2;
    			else
    			Nx[t][0]=Fa;
    		}
    		else
    		{
    			if (mx1>n-Size)
    			Nx[t][0]=mx2;
    			else
    			Nx[t][0]=Fa;
    		}
    		
    		fo(j,1,18)
    		Nx[t][j]=Nx[Nx[t][j-1]][j-1];
    		
    		k=t;
    		fd(j,18,0)
    		if (Nx[k][j] && size[t]-size[Nx[k][j]]<=size[t]/2)
    		k=Nx[k][j];
    		
    		ans+=k;
    		if (k!=t && !(size[t]&1) && size[t]-size[k]==size[t]/2)
    		ans+=fa[k];
    		
    		dfs2(t,a[i][0]);
    		
    		fa[t]=Fa;
    		size[t]=Size;
    	}
    	
    	fo(j,0,18)
    	Nx[t][j]=nx[t][j];
    }
    
    int main()
    {
    	freopen("centroid.in","r",stdin);
    	freopen("centroid.out","w",stdout);
    	
    	scanf("%d",&T);
    	for (;T;--T)
    	{
    		memset(ls,0,sizeof(ls));
    		ans=len=0;
    		
    		scanf("%d",&n);
    		fo(i,2,n)
    		{
    			scanf("%d%d",&j,&k);
    			
    			New(j,k);
    			New(k,j);
    		}
    		
    		dfs1(0,1);
    		
    		fo(i,1,n)
    		{
    			fo(j,0,18)
    			Nx[i][j]=nx[i][j];
    			
    			if (i>1)
    			{
    				k=i;
    				fd(j,18,0)
    				if (nx[k][j] && size[i]-size[nx[k][j]]<=size[i]/2)
    				k=nx[k][j];
    				
    				ans+=k;
    				if (k!=i && !(size[i]&1) && size[i]-size[k]==size[i]/2)
    				ans+=fa[k];
    			}
    		}
    		
    		dfs2(0,1);
    		
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    Atitit.atiRI  与 远程调用的理论and 设计
    Atitit.提升 升级类库框架后的api代码兼容性设计指南
    Atitit.研发管理软件公司的软资产列表指南
    Atitit.软件开发的三层结构isv金字塔模型
    Atitit.加密算法ati Aes的框架设计
    Atittit.研发公司的组织架构与部门架构总结
    IIS HTTP Error 500.24
    Visual Studio 快捷键
    软件学习遐想
    navigator属性
  • 原文地址:https://www.cnblogs.com/gmh77/p/12000506.html
Copyright © 2020-2023  润新知