zoukankan      html  css  js  c++  java
  • 9.16 牛客提高集训营2


    2018.9.16 牛客提高集训营2

    期望得分:100+40+10
    实际得分:100+10+10

    非要用滚动数组,还不好好清空,丢了30分吧。

    比赛链接

    A 方差

    题目链接

    拆一下方差的式子就可以(O(1))得到要求的值了。

    出题人:数据是精心设计的,刚好不会爆longlong。
    是的,这是在你原题面乘(n-1)而不是乘((n-1)^2)的情况下。
    longlong不好爆吗,((10^4)^2 imes 10^5 imes 10^5 imes 10^5=GG)。so数据(故意)水差评。
    输出格式真心有毒。

    #include <cstdio>
    #include <cctype>
    #include <iostream>
    #define gc() getchar()
    typedef long long LL;
    const int N=1e5+5;
    
    int n,A[N];
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    //void print(__int128 x)
    //{
    //	if(x<0) {x=-x; putchar('-');}
    //	if(x>9) print(x/10);
    //	putchar(x%10+'0');
    //}
    
    int main()
    {
    	n=read(); LL s1=0,s2=0;
    	for(int i=1; i<=n; ++i) s1+=(A[i]=read()),s2+=A[i]*A[i];
    //	if(n>2000)
    //	{
    //		__int128 ss1=s1,ss2=s2;
    //		for(int i=1; i<n; ++i)
    //		{
    //			__int128 aver2=ss1-A[i],tmp=ss2-A[i]*A[i];
    //			print(tmp*(n-1)-aver2*aver2), putchar(' ');
    //		}
    //		__int128 aver2=ss1-A[n],tmp=ss2-A[n]*A[n];
    //		print(tmp*(n-1)-aver2*aver2), putchar('
    ');
    //	}
    //	else
    	{
    		for(int i=1; i<n; ++i)
    		{
    			LL aver2=s1-A[i];
    			printf("%lld ",1ll*(n-1)*(s2-A[i]*A[i])-aver2*aver2);
    		}
    		LL aver2=s1-A[n];
    		printf("%lld
    ",1ll*(n-1)*(s2-A[n]*A[n])-aver2*aver2);
    	}
    	return 0;
    }
    

    B 分糖果(容斥 DP 单调栈)

    题目链接

    先考虑拆环为链,序列上怎么做。
    有限制不好做,考虑容斥。(Ans=无限制方案数-存在相邻至少2个相同+存在相邻至少3个相同ldots)
    每次确定相邻多少个相同就是分一段,这一段的方案数显然为这一段(A_i)的最小值。
    (f_i)表示考虑到(i)的答案。于是得到转移方程:$$f_i=sum_{j<i}f_j imesmin{a_{j+1},ldots,a_i} imes(-1)^{i-j-1}$$(i-j-1)即(这一段)有多少个相同。
    (或者我们考虑,第(i)个随便放:(f_i=f_{i-1} imes A_i),这样多算了(i)(i+1)相同的情况,所以再减去(f_{i-2} imesmin(A_i,A_{i-1})),...)
    首先把((-1)^i)提出来:$$f_i=(-1)^i imessum_{j<i}min{a_{j+1},ldots,a_i} imes f_j imes(-1)^{j+1}$$

    后面只与(j)有关。考虑怎么维护。当从(i)转移到(i+1)时:(min{a_{j+1},ldots,a_i} omin{a_{j+1},ldots,a_{i+1}}),只改变一项,可以用线段树取min、求和做。
    我们实际是在每个位置维护一个后缀最小值。
    1
    如图,当添加(i+1)时,会使(asim i+1)的最小值改变,即把(bsim c,csim i)这两段删去,添加新的一段(asim i+1)。可以用单调栈维护。

    然后是环的问题。即若(1)(n)相同则不合法。
    我们可以用不考虑环的(f[n]),减去不考虑环的(f[n-1]),即直接让(1)(n)相等(即不合法方案数)。但是又会多减(不用想感觉应该是这样...),所以再加(f[n-3])......
    还有个问题是合并时(a_1,a_n)是否可以取值相同。可以把最小的(A_i)转到(A_1)位置,这样就可以直接和最后一段合并。

    C 集合划分(构造)

    题目链接

    (m=0)

    (lb(x)=lowbit(x))表示(x)二进制下最低位的(1),即(x)集合内标号最小的元素。用(x|y)表示集合(x)(y)的并。
    那么:(lb(x))相同的元素全部分给一个人,这样构造的方案一定是合法的。
    证明:因为(lb(x|y))一定等于(lb(x))(lb(y)),所以若集合(x,y)都属于A,集合(x|y)也一定属于A。
    (lb(x)=i)(x)的个数恰好有(2^{n-i})个(比(i)大的(n-i)个元素任选),可以直接对(K)二进制拆分。

    (m>0)

    把上述做法推广,我们给每个元素定义一个优先级,使得不同元素优先级不同。
    然后对于一个集合,定义其"特征"为其中优先级最高的元素的编号。
    那么把特征相同的集合全部分给一个人,这样构造的方案一定是合法的。
    同时我们可以证明,对于所有方案都可以用这种方法构造。

    证明:
    假设 ({1,2,dots, n}in S)
    那么一定存在一个 (i) ,使得 (forall U) 使得 (iin U), 必有 (Uin S​) .
    (如果不存在,那么 (forall i, exists iin V_i, V_iin T) ,那么({1,2,dots, n}=igcup_i V_i in T),矛盾)
    不失一般性,交换(S,T)也成立。

    那么问题有两个:1.确定每个元素的优先级,从而计算集合的特征;2.把特征相同的集合分给同一个人。
    因为有(K)限制,哪些集合分给谁是确定的,即第二个问题不需要考虑。
    然后第一个问题我就看不懂了。
    求路过dalao解答

    考试代码

    B

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define Mod(x) x>=mod&&(x-=mod)
    #define mod 1000000007
    typedef long long LL;
    const int N=1e5+5;//1e6+5
    
    int n,A[N],ref[N],f[2][1005][1005];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline int Find(int x,int r)
    {
    	int l=1,mid;
    	while(l<r)
    		if(ref[mid=l+r>>1]<x) l=mid+1;
    		else r=mid;
    	return l;
    }
    inline int FP(int x,int k)
    {
    	int t=1;
    	for(; k; k>>=1,x=1ll*x*x%mod)
    		if(k&1) t=1ll*t*x%mod;
    	return t;
    }
    bool Spec1()
    {
    	int a=A[1];
    	for(int i=2; i<=n; ++i) if(A[i]!=a) return 0;
    	LL ans=0; int pw=a-1;
    	for(int i=1; i<=n-3; ++i,pw=1ll*pw*(a-1)%mod)
    		if((n-i)&1) ans+=1ll*a*pw%mod;
    		else ans-=1ll*a*pw%mod;
    	ans-=1ll*a*pw%mod;
    	pw=1ll*pw*(a-1)%mod, ans+=1ll*a*pw%mod;
    	printf("%d
    ",(int)((ans%mod+mod)%mod));
    	return 1;
    }/*
    8 10 10 10 10 10 10 10 10
    43046730*/
    
    int main()
    {
    	n=read();
    	for(int i=1; i<=n; ++i) ref[i]=A[i]=read();
    	if(n>100 && Spec1()) return 0;
    
    //	std::sort(ref+1,ref+1+n); int cnt=1;
    //	for(int i=2; i<=n; ++i) if(ref[i]!=ref[i-1]) ref[++cnt]=ref[i];
    //	for(int i=1; i<=n; ++i) A[i]=Find(A[i],cnt);
    
    	if(n>2000) return putchar('0'),0;
    
    	int now=0,las=1;
    	for(int i=1,a1=A[1]; i<=a1; ++i) f[las][i][i]=1;
    	for(int i=2,a1=A[1]; i<=n; ++i)
    	{
    		int lc=A[i-1],nc=A[i];
    		for(int j=1; j<=a1; ++j)
    		{
    			LL sum=0;
    			for(int k=1; k<=lc; ++k) sum+=f[las][j][k];
    			for(int k=lc+1; k<=nc; ++k) f[las][j][k]=0;//!!!
    			sum%=mod;
    //			if(!sum) continue;//...
    			for(int k=1; k<=nc; ++k) f[now][j][k]=(sum-f[las][j][k]+mod)%mod;
    		}
    		now=las, las^=1;
    	}
    	LL ans=0;
    	for(int i=1,a1=A[1]; i<=a1; ++i)
    		for(int j=1,an=A[n]; j<=an; ++j)
    			if(i!=j) ans+=f[las][i][j];
    	printf("%d
    ",(int)(ans%mod));
    
    	return 0;
    }
    

    C

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    const int N=(1<<18)+5;
    
    int n,m,lim,K,A[10005];
    bool OK,chose[N],need[N],inq[N];
    char ans[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    void DFS(int x,int sum)
    {
    	if(OK) return;
    	if(x>lim)
    	{
    		if(sum!=K) return;
    		for(int s1=1; s1<=lim; ++s1)
    			if(chose[s1])
    				for(int s2=1; s2<=lim; ++s2)
    					if(chose[s2] && !chose[s1|s2]) return;
    		OK=1;
    		for(int s=1; s<=lim; ++s) if(chose[s]) ans[s]='1';
    		return;
    	}
    	if(need[x])
    	{
    		if(sum>=K) return;
    		chose[x]=1, DFS(x+1,sum+1), chose[x]=0;
    	}
    	else
    	{
    		if(sum<K) chose[x]=1, DFS(x+1,sum+1), chose[x]=0;
    		DFS(x+1,sum);
    	}
    }
    bool Check1()
    {
    	static int q[N];
    	int h=0,t=0;
    	for(int i=1; i<=m; ++i) q[++t]=A[i],inq[A[i]]=1;
    	while(h<t)
    	{
    		int x=q[++h];
    		for(int i=1; i<=t; ++i)
    			if(!inq[x|q[i]]) inq[q[++t]=x|q[i]]=1;
    	}
    	if(t>K) return 0;
    	return 1;
    }
    
    int main()
    {
    	n=read(),m=read(),K=read(),lim=(1<<n)-1;
    	for(int s=0; s<=lim; ++s) ans[s]='0'; ans[lim+1]='';
    	for(int i=1; i<=m; ++i) need[A[i]=read()]=1;
    
    	if(m>K) return printf("-1"),0;
    	if(n<=4)
    	{
    		DFS(1,0);
    		if(OK)
    		{
    			for(int i=1; i<=lim; ++i) putchar(ans[i]);
    //			ans[lim+1]='', puts(ans+1);//mdzz
    		}
    		else printf("-1");
    		return 0;
    	}
    	if(1||!Check1()) return printf("-1"),0;
    	
    
    	return 0;
    }
    
    ------------------------------------------------------------------------------------------------------------------------
    无心插柳柳成荫才是美丽
    有哪种美好会来自于刻意
    这一生波澜壮阔或是不惊都没问题
    只愿你能够拥抱那种美丽
    ------------------------------------------------------------------------------------------------------------------------
  • 相关阅读:
    python中计算程序用时的方法
    既生list何生tuple
    SSAS-时间维度的标准设计
    1092 最好吃的月饼 (20 分
    1091 N-自守数 (15 分)
    1149 Dangerous Goods Packaging (25 分)
    1148 Werewolf
    1144 The Missing Number (20 分)
    1141 PAT Ranking of Institutions (25 分)
    1140 Look-and-say Sequence (20 分)
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9656831.html
Copyright © 2011-2022 走看看