[洛谷P3987]我永远喜欢珂朵莉~

本文介绍洛谷P3987题目“我永远喜欢珂朵莉~”的解题思路与源代码实现。针对给定的数组与操作,采用质因数分解、树状数组和离线处理等技巧进行高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[洛谷P3987]我永远喜欢珂朵莉~

题目大意:

给你\(n(n\le10^5)\)个数\(A_{1\sim n}(A_i\le5\times10^5)\)\(m(m\le5\times10^5)\)次操作,操作包含以下两种:

  1. 将区间\([l,r]\)间所有\(v\)的倍数除以\(v\)
  2. 求区间\([l,r]\)所有数之和。

思路1:

对范围内要用到的每个质因数开一个set维护包含该质因子的\(A_i\)下标。

对于操作\(1\),将\(v\)分解质因数,在set中查找下标在\([l,r]\)中的满足条件的数。并将这些数\(\div v\)。若操作过后不包含该质因数,则将其从set中删去。

对于操作\(2\),用树状数组维护即可。

源代码1:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<sys/mman.h>
#include<sys/stat.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
class MMapInput {
    private:
        char *buf,*p;
        int size;
    public:
        MMapInput() {
            register int fd=fileno(stdin);
            struct stat sb;
            fstat(fd,&sb);
            size=sb.st_size;
            buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0));
            p=buf;
        }
        char getchar() {
            return (p==buf+size||*p==EOF)?EOF:*p++;
        }
};
MMapInput mmi;
inline int getint() {
    register char ch;
    while(!isdigit(ch=mmi.getchar()));
    register int x=ch^'0';
    while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef __gnu_pbds::tree<int,__gnu_pbds::null_type,std::less<int>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update> rbtree;
typedef long long int64;
const int N=1e5+1,M=1e5,A=1e6+1,P=78499;
bool vis[A];
int a[N],n,m,p[P],fail[N];
inline void sieve() {
    for(register int i=2;i<A;i++) {
        if(vis[i]) continue;
        p[++p[0]]=i;
        for(register int j=i*2;j<A;j+=i) {
            vis[j]=true;
        }
    }
}
rbtree set[P];
class FenwickTree {
    private:
        int64 val[N];
        int lowbit(const int &x) const {
            return x&-x;
        }
    public:
        void modify(int p,const int &x) {
            for(;p<=n;p+=lowbit(p)) val[p]+=x;
        }
        int64 query(int p) const {
            int64 ret=0;
            for(;p;p-=lowbit(p)) ret+=val[p];
            return ret;
        }
        int64 query(const int &l,const int &r) const {
            return query(r)-query(l-1);
        }
};
FenwickTree t;
int main() {
    sieve();
    n=getint(),m=getint();
    for(register int i=1;i<=n;i++) {
        a[i]=getint();
        t.modify(i,a[i]);
        int tmp=a[i];
        for(register int j=1;p[j]*p[j]<=tmp;j++) {
            if(tmp%p[j]==0) {
                set[j].insert(i);
                while(tmp%p[j]==0) {
                    tmp/=p[j];
                }
            }
        }
        if(tmp!=1) {
            set[std::lower_bound(&p[1],&p[p[0]]+1,tmp)-p].insert(i);
        }
    }
    for(register int tim=1;tim<=m;tim++) {
        const int opt=getint();
        const int l=getint(),r=getint();
        if(opt==1) {
            const int tmp=getint();
            int v=tmp;
            for(register int i=1;p[i]*p[i]<=v;i++) {
                if(v%p[i]!=0) continue;
                int sum=1;
                for(;v%p[i]==0;v/=p[i]) sum*=p[i];
                const rbtree::iterator begin=set[i].lower_bound(l);
                const rbtree::iterator end=set[i].upper_bound(r);
                if(v==1) {
                    for(rbtree::iterator it=begin;it!=end;) {
                        if(a[*it]%p[i]!=0) {
                            set[i].erase(it++);
                            continue;
                        }
                        if(a[*it]%tmp==0&&fail[*it]<tim) {
                            t.modify(*it,a[*it]/tmp-a[*it]);
                            a[*it]/=tmp;
                        }
                        it++;
                    }
                    continue;
                }
                for(rbtree::iterator it=begin;it!=end;) {
                    if(a[*it]%p[i]!=0) {
                        set[i].erase(it++);
                        continue;
                    }
                    if(a[*it]%sum!=0) fail[*it]=tim;
                    it++;
                }
            }
            if(v!=1) {
                const int i=std::lower_bound(&p[1],&p[p[0]]+1,v)-p;
                const rbtree::iterator begin=set[i].lower_bound(l);
                const rbtree::iterator end=set[i].upper_bound(r);
                for(rbtree::iterator it=begin;it!=end;) {
                    if(a[*it]%v!=0) {
                        set[i].erase(it++);
                        continue;
                    }
                    if(a[*it]%tmp==0&&fail[*it]<tim) {
                        t.modify(*it,a[*it]/tmp-a[*it]);
                        a[*it]/=tmp;
                    }
                    it++;
                }
            }
        }
        if(opt==2) {
            printf("%lld\n",t.query(l,r));
        }
    }
    return 0;
}

思路2:

本题是某年CCF-CSP原题,用当时原题的数据,上面的做法是过不了的。

考虑不要按照质因数维护set,将操作离线,对于每个\(v\)维护一个set。然后卡卡常就过了。

源代码:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<sys/mman.h>
#include<sys/stat.h>
#include<ext/pb_ds/assoc_container.hpp>
class MMapInput {
    private:
        char *buf,*p;
        int size;
    public:
        MMapInput() {
            register int fd=fileno(stdin);
            struct stat sb;
            fstat(fd,&sb);
            size=sb.st_size;
            buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0));
            p=buf;
        }
        char getchar() {
            return (p==buf+size||*p==EOF)?EOF:*p++;
        }
};
MMapInput mmi;
inline int getint() {
    register char ch;
    while(!isdigit(ch=mmi.getchar()));
    register int x=ch^'0';
    while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=1e5+1,M=1e5,A=5e5+1;
int n,a[N];
struct Opt {
    int type,l,r,v;
};
Opt o[M];
std::set<int> set[M];
std::vector<int> vec;
int id[A];
class FenwickTree {
    private:
        int64 val[N];
        int lowbit(const int &x) const {
            return x&-x;
        }
    public:
        void modify(int p,const int &x) {
            for(;p<=n;p+=lowbit(p)) val[p]+=x;
        }
        int64 query(int p) const {
            int64 ret=0;
            for(;p;p-=lowbit(p)) ret+=val[p];
            return ret;
        }
        int64 query(const int &l,const int &r) const {
            return query(r)-query(l-1);
        }
};
FenwickTree t;
int main() {
    n=getint();
    const int m=getint();
    for(register int i=1;i<=n;i++) {
        t.modify(i,a[i]=getint());
    }
    for(register int i=0;i<m;i++) {
        o[i].type=getint();
        o[i].l=getint();
        o[i].r=getint();
        if(o[i].type==1) {
            o[i].v=getint();
            if(o[i].v==1) continue;
            vec.push_back(o[i].v);
        }
    }
    std::sort(vec.begin(),vec.end());
    vec.resize(std::unique(vec.begin(),vec.end())-vec.begin());
    std::fill(&id[0],&id[A],-1);
    for(register unsigned i=0;i<vec.size();i++) id[vec[i]]=i;
    for(register int i=1;i<=n;i++) {
        for(register int j=1;j*j<=a[i];j++) {
            if(a[i]%j!=0) continue;
            if(id[j]!=-1) set[id[j]].insert(i);
            if(id[a[i]/j]!=-1) set[id[a[i]/j]].insert(i);
        }
    }
    for(register int i=0;i<m;i++) {
        const int &opt=o[i].type,&l=o[i].l,&r=o[i].r;
        if(opt==1) {
            const int &v=o[i].v;
            if(v==1) continue;
            const std::set<int>::iterator begin=set[id[v]].lower_bound(l);
            const std::set<int>::iterator end=set[id[v]].upper_bound(r);
            for(register std::set<int>::iterator i=begin;i!=end;) {
                if(a[*i]%v!=0) {
                    set[id[v]].erase(i++);
                    continue;
                }
                t.modify(*i,a[*i]/v-a[*i]);
                a[*i]/=v;
                if(a[*i]%v!=0) {
                    set[id[v]].erase(i++);
                    continue;
                }
                ++i;
            }
        }
        if(opt==2) {
            printf("%lld\n",t.query(l,r));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/skylee03/p/9379168.html

### 关于洛谷 B3987 朋友数列问题 针对洛谷平台上的编号为B3987的朋友数列题目,该题目的核心在于理解两个数字成为“朋友”的定义以及如何高效计算满足条件的数对数量。 #### 定义与目标 在这个问题中,“朋友”关系被定义为如果一对正整数\(A\)和\(B\)之间存在某种特定的关系,则认为它们互为朋友。具体来说,当且仅当\(A \% 10 = \lfloor B / 10 \rfloor\) 或者 \(B \% 10 = \lfloor A / 10 \rfloor\) 成立时,\(A\) 和 \(B\) 是朋友。这里\(\%\),表示取模运算;而\(\lfloor x \rfloor\)代表不大于\(x\)的最大整数(向下取整)。任务是在给定范围内找出所有的朋友数对并返回其总数[^1]。 #### 解决方案概述 为了有效地解决这个问题,可以采用计数排序的思想来优化查询过程: - **预处理阶段**:创建一个数组用于记录各个可能作为十位或个位数值出现次数; - **遍历区间内的每一个数**:对于当前考察中的每个数,依据上述规则快速定位潜在的朋友候选对象,并通过预先构建好的辅助结构加速匹配操作; - **统计符合条件的结果数目**:每当发现一组新的朋友组合就增加计数器直至完成整个范围扫描为止。 下面给出一段Python代码示例实现了这一思路: ```python def count_friend_pairs(L, R): cnt = [0]*10 # 统计L到R之间的每一位数字出现频率 for num in range(L, R + 1): last_digit = num % 10 first_digit = (num // 10) % 10 if num >= 10 else 0 cnt[last_digit] += 1 if first_digit != last_digit: cnt[first_digit] += 1 result = sum((v * (v - 1)) >> 1 for v in cnt) return result if __name__ == "__main__": L, R = map(int, input().split()) print(count_friend_pairs(L, R)) ``` 这段程序首先初始化了一个大小为10的列表`cnt`用来存储从0至9这十个不同数码在整个闭合区间\[L,R\]内各自出现了几次。接着,在循环体内更新这些统计数据的同时也考虑到了那些只有一位有效数字的情况。最后一步则是利用组合数学原理——即任意选取两件物品的方法数等于C(n,2)=n*(n−1)/2—来进行最终答案的汇总工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值