【比赛报告】2018.10.30牛客网线上赛[牛客网NOIP赛前集训营-提高组(第二场)] NOIP练习赛卷二十五
A.方差 前缀和
我们把方差公式进行化简。记 为每个数的前缀和, 为每个数平方后的前缀和
于是我们要求的答案为
求出前缀和后每一步可以 求出解
#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+输出方案