这是截至 2022.1.9 我提交次数最多的题目之一。
咱们一步一步来。
我们随便打个暴力:
while(m--)
{
int op,l,r,x;
cin>>op>>l>>r;
if(op==1)
{
cin>>x;
for(int i=l;i<=r;i++)
{
if(a[i]%x==0) a[i]/=x;
}
}
else
{
int s=0;
for(int i=l;i<=r;i++)
{
s+=a[i];
}
cout<<s<<endl;
}
}
「恭喜你获得了 12 pts 12\text{pts} 12pts 的好成绩。」
诶?为什么有一点 WA 了?
哦!
不开 long long
见祖宗!
int s=0;
→long long s=0;
。
「恭喜你获得了
15
pts
15\text{pts}
15pts 的好成绩。」
听取 TLE 声一片……试试 O2?
「恭喜你获得了
88
pts
88\text{pts}
88pts 的好成绩。」
质的飞跃。
还是有几点 T 了……
试试快读快出?
试试就逝世。
「恭喜你获得了
88
pts
88\text{pts}
88pts 的好成绩。」
啊这……
等下!
当操作一的
x
=
1
x=1
x=1 时,
a
i
1
=
a
i
\frac{a_i}{1}=a_i
1ai=ai,不需要做!
if(x==1) continue;
「恭喜你获得了 91 pts 91\text{pts} 91pts 的好成绩。」
让我看看 #1 是什么情况……
刚才是
x
=
1
x=1
x=1,那
x
=
2
x=2
x=2 呢……
诶它是
2
2
2 的次幂,可以位运算诶!
卡常大法……对!再循环展开!
「恭喜你获得了
100
pts
100\text{pts}
100pts 的好成绩。」
氢氧根离子。
AC Code(+O2):
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],i;//i 放在这是避免多次定义
long long s;
int read()//快读
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void write(long long x)//快出
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
}
while(m--)
{
int op=read(),l=read(),r=read(),x;
if(op==1)//操作一
{
x=read();
if(x==1) continue;//x=1 的特判
if(x==2)//x=2 的特判
{
for(i=l;i<=r-5;i+=6)
{//循环展开
!(a[i]&1)?a[i]>>=1:1;
!(a[i+1]&1)?a[i+1]>>=1:1;
!(a[i+2]&1)?a[i+2]>>=1:1;
!(a[i+3]&1)?a[i+3]>>=1:1;
!(a[i+4]&1)?a[i+4]>>=1:1;
!(a[i+5]&1)?a[i+5]>>=1:1;
}
while(r-i+1)
{//当不够展开时的补充
!(a[i]%x)?a[i]/=x:1;
i++;
}
}
else
{
for(i=l;i<=r-5;i+=6)
{//循环展开
!(a[i]%x)?a[i]/=x:1;
!(a[i+1]%x)?a[i+1]/=x:1;
!(a[i+2]%x)?a[i+2]/=x:1;
!(a[i+3]%x)?a[i+3]/=x:1;
!(a[i+4]%x)?a[i+4]/=x:1;
!(a[i+5]%x)?a[i+5]/=x:1;
}
while(r-i+1)
{
!(a[i]%x)?a[i]/=x:1;
i++;
}
}
}
else//操作二
{
s=0;
for(i=l;i<=r-5;i+=6)
{//循环展开
s+=a[i]+a[i+1]+a[i+2]+a[i+3]+a[i+4]+a[i+5];
}
while(i<=r)
{
s+=a[i++];
}
write(s);
puts("");
}
}
return 0;
}