P10704题解 数论分块
思路
第一眼看到这题,想到的就是数论分块。可以参见 P2261。
但显然还是有点不同的,因为这题有两个求和,该怎么办呢?
我稍微思考了一下,发现就是
但是这里数论分块貌似有点特殊,因为分母不都是连续的,看来只能离散化然后每次二分或者倍增跳,很好很好。
感觉没什么问题,算一下复杂度是
-
\sum\limits_{i=1}^{n}a_i\le10^9
没错这东西肯定是有用的,因为
不愧是我。复杂度
代码
以下为代码参考。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const ll mod=998244353;
ll n,m,a[N],ans,g[N],c[N],sumc[N],tot;
int main()
{
scanf("%lld%lld",&n,&m);
for (int i=1;i<=n;i++)scanf("%lld",&a[i]);
sort(a+1,a+n+1);
ll cnt=0;
for (int i=1;i<=n;i++)
{
if (a[i]!=a[i-1])c[tot]=cnt,g[++tot]=a[i],cnt=1;
else cnt++;
}
c[tot]=cnt;
for (int i=1;i<=tot+1;i++)sumc[i]=sumc[i-1]+c[i];
for (int t=1;t<=tot;t++)
{
ll k=m/g[t];
for (int i=g[1],j,pos=1,lpos;i<=1e9 && j<=1e9 && pos<=tot;i=g[pos])
{
if (k/i)j=min(k,k/(k/i));
else j=1e9;
lpos=pos-1;
pos=upper_bound(g+1,g+tot+1,j)-g;
ans+=(k/i)%mod*c[t]%mod*(sumc[pos-1]-sumc[lpos])%mod;
ans%=mod;
if (i>g[tot])break;
}
}
printf("%lld",ans);
return 0;
}
稍微有点丑陋,不管了。