D1302-GCD 题解
前言
好的阅读的时候或者复制的时候记得删掉这一段
找我要 LaTeX 我也不会给这一段
这一次没有认真打,把 T1 弄过去就直接睡觉了所以没有写 T2
所以这一次没有办法写 T2 只能写 T1
那就开始吧
题目
题目意思
给出一个长度为 \(n\) 的数组 \(a_i\),每次询问有两种操作,一种是删除一个数 \(a_x\),保证这个数还没有被删掉,另一种是查询 \(a\) 现在里面的所有数字的 \(GCD\) 值,输出所有查询的和对一个数字取模。
做法
我的做法可能和题解的不一样但是个人认为可以更好理解和想到
因为发现他居然只要输出所有查询的和,所以说明不需要按照顺序处理问题
首先我们删掉的数字是有一定顺序的,所以我们可以按照他们被删掉的先后顺序排序,如果没有被删掉就扔到最后面,比如 \(1\ 3\ 2\ 5\ 4\) 的删除顺序为 \(1\ 4\ 2\) 那么我们可以将他排序变成 \(1\ 5\ 3\ 2\ 4\)
这样的话有什么用呢?我们发现查询的时候一定是查询的一个后缀,因为每一次删除相当于都是删除了开头的那个数字,那么我们只需要统计一个后缀 GCD 即可。
接下来考虑询问
这里开始可能有点难理解了
因为我们每一次询问是询问的一个后缀,所以我们可以考虑对后缀计数
具体而言,我们记录每一个后缀到底加了几次,如果现在删除了 \(num\) 次数字了,那么就说明还剩下 \(n-num\) 个数字,也就是要统计一次 \(n-num\) 个长度的后缀,所以开一个桶 \(book_i\) 表示从 \(i\) 到 \(n\) 的这个后缀到底统计了多少次,那么每一次询问假设删除了 \(p\) 个数字,\(book_{p+1}\) 加上 \(1\) 就可以了。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e6+9,mod=998244353;
struct num{ll x,id;}a[N];
inline bool cmp(num x,num y){
return x.id<y.id;
}
ll n,m,cnt,sum[N],que[N];
inline void solve(){
cnt=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i].x;
for(int i=0;i<=n+1;i++)
a[i].id=INT_MAX,que[i]=0,sum[i]=0;
for(int i=1;i<=m;i++){
int x;
cin>>x;
if(x) a[x].id=++cnt;
else que[cnt]++;
}
sort(a+1,a+n+1,cmp);
ll ans=0;
for(int i=n;i>=1;i--)
sum[i]=__gcd(sum[i+1],a[i].x),
ans=(ans+sum[i]*que[i-1])%mod;
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--){
solve();
}
return 0;
}

浙公网安备 33010602011771号