世界未末日 加强版 题解
VinstaG173 · · 题解
数据范围:
首先原来的做法显然用不了了。我们考虑找一下 dSG 函数(即从 SG 值对应回最少石子数的函数)的性质。
我们发现数列长这样(称为数列
差分一下(得到的数列称为数列
再差分一下(得到的数列称为数列
发现数列
首先我们尝试解数列
令
那么我们可以分别求
令
令
因此数列
然后由于暴力求每个二进制位上数值和是
考虑分治计算贡献。设所有 SG 值最大的二进制位数为
对于每段,先将每个数这一段中二进制位对应的所有可能取值出现次数用一个下标为
然后对于这
这样的时间复杂度是
总时间复杂度是
Code:
#include<cmath>
#include<cstdio>
#define rg register
#define ll long long
#define lb(x) (x&(-x))
inline char gc()
{
static char buf[1048576],*pn=buf,*pe=buf;
return (pn==pe)&&(pe=(pn=buf)+fread(buf,1,1048576,stdin),pn==pe)?EOF:*pn++;
}
inline int read()
{
int x=0;
char cc=gc();
while(cc<'0'||cc>'9')cc=gc();
while(cc>='0'&&cc<='9')x=x*10+cc-'0',cc=gc();
return x;
}
inline ll _read()
{
ll x=0;
char cc=gc();
while(cc<'0'||cc>'9')cc=gc();
while(cc>='0'&&cc<='9')x=x*10+cc-'0',cc=gc();
return x;
}
ll S,s;
int n,k;
int t,w,m;
int v,flag;
ll ssmv[37];
int cnt[37],pw2[17];
int x[37],sm[37],ssm[37];
int cnt1[32773],cnt2[32773];
int ans1[32773],ans2[32773];
int main()
{
n=read(),k=read()+1,S=_read();
while(1ll<<(m<<1)<=S)++m;
--m,t=(m>>1)+1,w=(1<<t)-1;
pw2[0]=x[1]=sm[1]=ssm[1]=1;
for(rg int i=1;i<t;++i)pw2[i]=(pw2[i-1]<<1);
for(rg int i=2;i<=m;++i)
{
x[i]=(x[i-1]<<1)|(i&1),sm[i]=sm[i-1]+x[i];
ssm[i]=ssm[i-1]+sm[i],ssmv[i]=(sm[i]+3ll+i)*sm[i]-ssm[i];
}
for(rg int i=0,l,r,mid;i<n;++i)
{
s=_read(),l=0,r=m;
while(l<r)mid=r-((r-l)>>1),(ssmv[mid]<=s)?(l=mid):(r=mid-1);
v=int((sqrt((l+3)*(l+3)+((s+ssm[l])<<2))-l-3)/2),++cnt1[v&w],++cnt2[v>>t];
}
for(rg int i=0;i<=w;++i)
{
for(rg int j=i;j;j^=lb(j))
{
ans1[lb(j)]+=cnt1[i];
}
}
for(rg int i=0;i<t;++i)cnt[i]=ans1[pw2[i]];
for(rg int i=0;i<=w;++i)
{
for(rg int j=i;j;j^=lb(j))
{
ans2[lb(j)]+=cnt2[i];
}
}
for(rg int i=0;i<t;++i)cnt[i+t]=ans2[pw2[i]];
for(rg int i=0;i<=m;++i)(cnt[i]%k)&&(flag=1);
puts((flag)?"YES":"NO");
return 0;
}
关于解法中关于 如果证明很简单请顺带把我这个垃圾爆踩一顿