P3987
我永远喜欢珂朵莉~
题目描述
给珂朵莉一个长为 \(n\) 的非负数序列 \(a\),支持以下两个操作:
- \(\verb!1 l r x!\):把区间 \([l,r]\) 中所有 \(x\) 的倍数除以 \(x\)。
- \(\verb!2 l r!\):查询区间 \([l,r]\) 内元素的和。
珂朵莉很可爱,所以你要帮珂朵莉写这个题。
输入格式
第一行两个数表示 \(n,m\)。
第二行 \(n\) 个非负整数表示 \(a_i\)。
之后 \(m\) 行每行一个操作:
- \(\verb!1 l r x!\):把区间 \([l,r]\) 中所有 \(x\) 的倍数除以 \(x\)。
- \(\verb!2 l r!\):查询区间 \([l,r]\) 内元素的和。
输出格式
对于每次询问,输出一行一个数表示答案。
样例 #1
样例输入 #1
5 3
1 2 3 4 5
2 1 5
1 1 5 2
2 1 5
样例输出 #1
15
12
提示
数据范围及约定
\(1 \le n , m \le 10^5\),\(0 \le a_i \le 5\times 10^5\),\(1 \le x \le 5\times 10^5\)。
本来是一道毒瘤数据结构题
但是 暴力+卡常就能A!
暴力很好写
点击查看代码
for(register int i=1;i<=n;++i)a[i]=read();
while(m--)
{
int op,l,r,x;
op=read(),l=read(),r=read();
if(op==1)
{
x=read();
for(register int i=l;i<=r;++i)
if(!(a[i]%x))
a[i]/=x;
}
else
{
long long sum=0;
for(register int i=l;i<=r;i++)
sum+=a[i];
write(sum);
printf("\n");
}
}
可以发现加了个快读 快写 register优化后就可以得88pts!!!
其实 这个优化的重点是
能开int就开int!!!超出范围再开long long
不要用#define int long long
long long 很慢!
继续优化
将变量全部定义在循环外面 加上register
循环展开
四个一组可以充分激活并发器提高运行效率
点击查看代码
for(i=l;i<=r-3;i+=4)
{
if(!(a[i]%x))
a[i]/=x;
if(!(a[i+1]%x))
a[i+1]/=x;
if(!(a[i+2]%x))
a[i+2]/=x;
if(!(a[i+3]%x))
a[i+3]/=x;
}
while(r-i+1)
{
if(!(a[i]%x))a[i]/=x;
++i;
}
这样就有97pts了
还有一个优化
取模运算和除法运算特别慢!
所以我们可以特判x=2,4,8等2的幂次的情况
这样!(a[i]%x)可以写成!(a[i]&1) a[i]/=x可以写成a[i]>>=1
利用位运算的超快速度就可以AC这道题了
AC
#include<bits/stdc++.h>
using namespace std;
int a[500005];
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
int x=0,f=1;
char ch=nc();
while(ch<48||ch>57)
{
if(ch=='-')
f=-1;
ch=nc();
}
while(ch>=48&&ch<=57)
x=x*10+ch-48,ch=nc();
return x*f;
}
void write(long long x)
{
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
int main()
{
ios::sync_with_stdio(false);
register int n=read(),m=read(),l,r,op,i,x;
register long long sum;
for(i=1;i<=n;++i)a[i]=read();
while(m--)
{
op=read(),l=read(),r=read();
if(op==1)
{
x=read();
if(x==2)
{
for(i=l;i<=r-3;i+=4)
{
if(!(a[i]&1))
a[i]>>=1;
if(!(a[i+1]&1))
a[i+1]>>=1;
if(!(a[i+2]&1))
a[i+2]>>=1;
if(!(a[i+3]&1))
a[i+3]>>=1;
}
while(r-i+1)
{
if(!(a[i]&1))a[i]>>=1;
++i;
}
}
else
{
for(i=l;i<=r-3;i+=4)
{
if(!(a[i]%x))
a[i]/=x;
if(!(a[i+1]%x))
a[i+1]/=x;
if(!(a[i+2]%x))
a[i+2]/=x;
if(!(a[i+3]%x))
a[i+3]/=x;
}
while(r-i+1)
{
if(!(a[i]%x))a[i]/=x;
++i;
}
}
}
else
{
sum=0;
for(i=l;i<=r-3;i+=4)
sum+=a[i]+a[i+1]+a[i+2]+a[i+3];
while(r-i+1)sum+=a[i++];
write(sum);
putchar('\n');
}
}
return 0;
}
此生无悔入OI 来生AK IOI

浙公网安备 33010602011771号