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;
}
posted @ 2023-01-17 11:27  PKU_IMCOMING  阅读(4)  评论(0)    收藏  举报