1. 程式人生 > >【比賽報告】2018.10.30牛客網線上賽[牛客網NOIP賽前集訓營-提高組(第二場)] NOIP練習賽卷二十五

【比賽報告】2018.10.30牛客網線上賽[牛客網NOIP賽前集訓營-提高組(第二場)] NOIP練習賽卷二十五

比賽連結

A.方差 字首和

題目連結
在這裡插入圖片描述
在這裡插入圖片描述


我們把方差公式進行化簡。記 s u m 1 sum_1 為每個數的字首和, s

u m 2 sum_2 為每個數平方後的字首和
1 m
i = 1 m ( b i
b ) 2 = 1 m i = 1 m ( b i 2 2 b i b + b 2 ) = 1 m ( s u m 2 2 b s u m 1 + m b 2 ) = 1 m ( s u m 2 2 s u m 1 2 m + s u m 1 2 m ) = s u m 2 m s u m 1 2 m 2 \frac{1}{m}\sum_{i=1}^m(b_i-\overline{b})^2\\=\frac{1}{m}\sum_{i=1}^m(b_i^2-2*b_i*\overline{b}+\overline{b}^2)\\=\frac{1}{m}(sum_2-2*\overline{b}*sum_1+m*\overline{b}^2)\\=\frac{1}{m}(sum_2-2*\frac{sum_1^2}{m}+\frac{sum_1^2}{m})\\=\frac{sum_2}{m}-\frac{sum_1^2}{m^2}

於是我們要求的答案為
( n 1 ) ( s u m 2 a i 2 ) ( s u m 1 a i ) 2 (n-1)*(sum_2-a_i^2)-(sum_1-a_i)^2
O ( n ) O(n) 求出字首和後每一步可以 O ( 1 ) O(1) 求出解

#include<cstdio>
typedef long long ll;
const int N=1e5+10;
int n,a[N];
ll sum2,sum1;
int main()
{
	//freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	    scanf("%d",&a[i]),sum1+=a[i],sum2+=a[i]*a[i];
	for(int i=1;i<=n;i++)
	    printf("%lld ",(n-1)*(sum2-a[i]*a[i])-(sum1-a[i])*(sum1-a[i]));
	return 0;
}

總結

主考公式化簡


B.分糖果 單調棧優化線性DP+容斥原理

題目連結
在這裡插入圖片描述
在這裡插入圖片描述


在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

#include<cstdio>
#define re register
typedef long long ll;
const int N=1e6+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
template<typename tp>inline int getmin(tp&x,tp y){return y<x?x=y,1:0;}
template<typename tp>inline int getmax(tp&x,tp y){return y>x?x=y,1:0;}
template<typename tp>inline void read(tp&x)
{
	x=0;re int f=0;re char ch=getchar();
	while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	if(f)x=-x;
}
template<typename tp>inline void write(tp x)
{
	re int buf[40],p=0;
	if(x<0)putchar('-'),x=-x;
	do{
		buf[p++]=x%10;x/=10;
	}while(x);
	for(re int i=p-1;i+1;i--)putchar(buf[i]+48);
	putchar('\n');
}
template<typename tp>inline int add(tp x,tp y){return x+y>=mod?x+y-mod:x+y;}
template<typename tp>inline int dec(tp x,tp y){return x-y<0?x-y+mod:x-y;}
template<typename tp>inline int mul(tp x,tp y){return 1ll*x*y%mod;}
int n,mn=INF,a[N],pos,b[N],sta[N],val[N],f[N],sum,top;
int main()
{
	//freopen("in.txt","r",stdin);
    read(n);
    for(re int i=1;i<=n;i++)
    {
    	read(a[i]);
    	if(getmin(mn,a[i]))pos=i;
	}
	for(re int i=1;i<=n;i++)
	    b[i]=a[(pos+i-2)%n+1];
	sta[++top]=1;val[1]=b[1];f[1]=b[1];
	for(re int i=2;i<=n;i++)
	{
		sta[++top]=i;val[i]=f[i-1];
		while(top>1&&b[sta[top-1]]>b[sta[top]])
		{
			if((i-sta[top-1])&1)
			{
				val[i]=dec(val[i],val[sta[top-1]]);
				sum=dec(sum,mul(b[sta[top-1]],val[sta[top-1]]));
			}
			else
			{
				val[i]=add(val[i],val[sta[top-1]]);
				sum=add(sum,mul(b[sta[top-1]],val[sta[top-1]]));
			}
			sta[top-1]=sta[top];top--;
		}
		sum=dec(mul(b[i],val[i]),sum);
		if(i&1)f[i]=add(sum,f[1]);
		else f[i]=dec(sum,f[1]);
	}
	for(re int i=top;i>1;i--)
	{
		if((n-sta[i])&1)f[n]=add(f[n],val[sta[i]]);
		else f[n]=dec(f[n],val[sta[i]]);
	}
	f[n]=(n&1?dec(f[n],f[1]):add(f[n],f[1]));
	write(f[n]);return 0;
}

總結

容斥原理結合單調棧DP好題


C.集合劃分 狀壓DP

題目連結
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述


在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
看了題解後還是沒寫對,只能去看Komachi大佬咋寫的了。

#include<cstdio>
#include<cstring>
const int N=18,MX=(1<<18)+5;
int n,m,k,ban[N][MX],pre[MX],f[MX];
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1,x;i<=m;i++)//一定給小s的集合 
    {
    	scanf("%d",&x);
    	for(int i=0;i<n;i++)
    	    if(x&(1<<i))
    	        ban[i][x]=1;//標記集合x中的i位
	}
	for(int i=0;i<n;i++)
	    for(int j=0;j<(1<<n);j++)
	        if(ban[i][j])
	            for(int k=0;k<n;k++)
	                if(!(j&(1<<k)))
	                    ban[i][j|(1<<k)]=1;
    f[0]=1;int S=(1<<n)-1;
	for(int i=0;i<(1<<n);i++)
	    if(f[i])
	    {
	    	int t=0;
	    	for(int j=0;j<n;j++)
	    	    t+=(i>>j)&1;
	    	t=1<<n-t-1;
	    	for(int j=0;j<n;j++)
	    	    if(!(i&(1<<j))&&((k&t)||(!ban[j][S^i])))
	    	        pre[i|(1<<j)]=i,f[i|(1<<j)]=1;
		}
	if(!f[S])puts("-1");
	else
	{
		memset(f,0,sizeof(f));
		for(int t=0,p=S;p;p=pre[p],t++)
		    if(k&(1<<t))
		    {
		    	int d=p^pre[p],i=p^S;
		    	for(int j=i;j;j=(j-1)&i)
		    	    f[d|j]=1;
		    	f[d]=1;
			}
		for(int i=1;i<(1<<n);i++)
		    putchar(f[i]^48);
		puts("");
	}
	return 0;
}

總結

狀壓DP+輸出方案