luogu P5355 [Ynoi2017]由乃的玉米田
Ynoi虐我千百遍,我待sjjg如初见
话说\(Ynoi\)真是毒瘤,不开寄存器居然过不去。
这道题前三问可以从小清新人渣的本愿过来,开个\(bitset\)暴力乱搞就好了。
主要是第四问。
考虑暴力乱搞(这还要考虑?),那么\(x=1\)的时候复杂度将会很高,达到了\(\frac{n}{w}\)。
考虑优化。
采用数据分治,将第四种运算中的\(x\leq s\)的点拿出来单独算。
我们可以对每一个拿出来的\(x\)暴力莫队,在过程中统计个数,最后确定个数。设拿出来\(y\)个,时间复杂度\(O((sn+y)\sqrt n)\),所以\(s\)不便过大。
那么\(s\)取多少呢?
如果满足数据随机分布,我们要让\(y\sqrt n < \frac{n}{w}\),则在当前\(10^5\)的数据下,\(y\leq 9\),经手动二分 精确计算\(y\)取值在\(5\)最好。那么\(s\)的取值也基本为这个数。
那你是不是以为这样就过了呢?
不,你得卡常!
代码实现:
#include<cstdio>
#include<algorithm>
#include<bitset>
#include<cmath>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,a[100039],ans[100039],s[100039],tot,now,head,pus,tmp,tots;
struct yyy{
int x,y,z,now,num;
}f[100039],g[100039];
inline bool cmp(yyy x,yyy y){
return (x.x/k==y.x/k)?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x;
}
inline bool cmp1(yyy x,yyy y){
if(x.z!=y.z) return x.z<y.z;
return (x.x/k==y.x/k)?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x;
}
inline void read(int &x){
char s=getchar();x=0;
while(s<'0'||s>'9') s=getchar();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
bitset<100039> s1,s2;
int main(){
//freopen("1.in","r",stdin);
register int i,l=1,r=0,j,h;
register yyy tmps;
scanf("%d%d",&n,&m);
k=sqrt(n);
for(i=1;i<=n;i++) read(a[i]),tot=max(tot,a[i]);
//pus=sqrt(tot);
for(i=1;i<=m;i++){
read(now);read(x);read(y);read(z);
if(now==4&&z<5&&z!=0)g[++tmp]=(yyy){x,y,z,now,i};
else f[++head]=(yyy){x,y,z,now,i};
}
sort(f+1,f+head+1,cmp);
for(i=1;i<=head;i++){
tmps=f[i];
while(l<tmps.x){
s[a[l]]--;
if(!s[a[l]])s1[a[l]]=0,s2[tot-a[l]]=0;
l++;
}
while(r>tmps.y){
s[a[r]]--;
if(!s[a[r]])s1[a[r]]=0,s2[tot-a[r]]=0;
r--;
}
while(l>tmps.x){
l--;
s[a[l]]++;
if(s[a[l]]==1)s1[a[l]]=1,s2[tot-a[l]]=1;
}
while(r<tmps.y){
r++;
s[a[r]]++;
if(s[a[r]]==1)s1[a[r]]=1,s2[tot-a[r]]=1;
}
if(tmps.now==1)ans[tmps.num]=(s1&(s1<<tmps.z)).any();
if(tmps.now==2)ans[tmps.num]=(s1&(s2>>(tot-tmps.z))).any();
if(tmps.now==3){
for(j=1;j*j<=tmps.z;j++) if(tmps.z%j==0&&(s1[j]&s1[tmps.z/j])) {ans[tmps.num]=1;break;}
}
if(tmps.now==4){
if(tmps.z==0) ans[tmps.num]=((s1.count()-s1[0]>=1)&&s1[0]);
else for(j=1;j*tmps.z<=tot;j++) if(s1[j]&s1[j*tmps.z]){ans[tmps.num]=1;break;}
}
}
sort(g+1,g+tmp+1,cmp1);
for(i=1;i<=tmp;i++){
for(j=i;j<=tmp;j++) if(g[j].z!=g[j+1].z) break;
l=1;r=0;tots=0;
memset(s,0,sizeof(s));
for(h=i;h<=j;h++){
tmps=g[h];
while(r<tmps.y){
r++;
s[a[r]]++;
if(a[r]*tmps.z<=tot)tots+=s[a[r]*tmps.z];
if(a[r]%tmps.z==0) tots+=s[a[r]/tmps.z];
}
while(l>tmps.x){
l--;
s[a[l]]++;
if(a[l]*tmps.z<=tot)tots+=s[a[l]*tmps.z];
if(a[l]%tmps.z==0)tots+=s[a[l]/tmps.z];
}
while(r>tmps.y){
if(a[r]*tmps.z<=tot) tots-=s[a[r]*tmps.z];
if(a[r]%tmps.z==0) tots-=s[a[r]/tmps.z];
s[a[r]]--;
r--;
}
while(l<tmps.x){
if(a[l]*tmps.z<=tot) tots-=s[a[l]*tmps.z];
if(a[l]%tmps.z==0)tots-=s[a[l]/tmps.z];
s[a[l]]--;
l++;
}
//printf("%d %d %d %d\n",l,r,g[h].z,tots);
if(tots) ans[tmps.num]=1;
}
i=j;
}
for(i=1;i<=m;i++){
if(ans[i]) printf("yuno\n");
else printf("yumi\n");
}
}
\(111\)行,\(2846\)字节。已经算是\(Ynoi\)中代码量很少的一部分题了。

浙公网安备 33010602011771号