【暴摸+优化】洛谷P1483 序列变换

链接

https://www.luogu.org/problemnew/show/P1483


大意

给定一个长度为 n n 的序列,要求支持以下操作
1. 支持编号是 x x 的倍数的所有数同时加上 y y
2. 输出编号为 x x 的数


思路

比较容易想到一种朴素的思路

维护一个数组 b b bi b i 表示 i i 这个位置的增值,然后在修改的时候暴力改,时间复杂度最坏为 O(mn) O ( m n ) ,此方法可拿70分

又想到另一种 O(1) O ( 1 ) 修改,考虑优化回答的方法,首先预处理所有数的因数,然后回答的时候找到 x x 的所有因数,加上其对应的 bi b i 即可
这种方法的理论时间复杂度为 O(nlogn+mlogn) O ( n l o g n + m l o g n ) ,由于常数大了一点,所以只能拿70

考虑去优化上面的方法,回答的时候直接加上这个编号的因数上的 b b ,即可求出最终答案,时间复杂度最坏为 O(nm) O ( n m ) ,可以卡过本题。


代码1

#include
using namespace std;int n,m,a[1000001],x,y,b[1000001],k;
int read()
{
    char c;int d=1,f=0;
    while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline void write(register int x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
    n=read();m=read();
    for(register int i=1;i<=n;i++) a[i]=read();
    while(m--)
    {
        k=read()-1;
        if(k) 
        {
            x=read();
            write(a[x]+b[x]);putchar(10);//O(1)回答
        }
        else 
        {
            x=read();y=read();
            for(register int j=x;j<=n;j+=x) b[j]+=y;//朴素更改
        }
    }
}

代码2

#include
#include
using namespace std;int n,m,a[1000001],x,y,b[1000001],ans,k;
vector<int>factor[1000001];
int read()
{
    char c;int d=1,f=0;
    while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline void write(register int x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
    n=read();m=read();
    for(register int i=1;i<=n;i++)
     for(register int j=1;j<=n/i;j++)
      factor[i*j].push_back(i);//预处理
    for(register int i=1;i<=n;i++) a[i]=read();
    while(m--)
    {
        k=read()-1;
        if(k) 
        {
            x=read();
            ans=a[x];
            for(register int i=0;i//找到约数并且输出
            write(ans);putchar(10);
        }
        else x=read(),y=read(),b[x]+=y;
    }
}

代码3

#include
using namespace std;int n,m,a[1000001],x,y,b[1000001],ans,k;
int read()
{
    char c;int d=1,f=0;
    while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline void write(register int x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
    n=read();m=read();
    for(register int i=1;i<=n;i++) a[i]=read();
    while(m--)
    {
        k=read()-1;
        if(k) 
        {
            x=read();
            ans=a[x];
            for(register int i=1;i*i<=x;i++) 
            {
                if(x%i) continue;//找到是x因数的数
                ans+=b[i];if(i!=x/i) ans+=b[x/i];//因为因数都是成对出现的,所以可以直接加,注意判断完全平方数
            }
            write(ans);putchar(10);
        }
        else x=read(),y=read(),b[x]+=y;//O(1)修改
    }
}

你可能感兴趣的:(模拟)