【noi.ac-CSP-S全国模拟赛第三场】#705. mmt
给定数组a[],b[]
求$$c_i=\sum_{j=1}^{i} a_{\left \lfloor \frac{n}{j} \right \rfloor}·b_{i \bmod j}$$
大概就是对于每一个n求上面那个式子,显然数论分块
乱搞有$$c_n=\sum_{i=1}^{n} a_{\left \lfloor \frac{n}{i} \right \rfloor}·b_{n-\lfloor \frac{n}{i} \rfloor * i}$$
当在同一块内,也就是$\lfloor \frac{n}{i} \rfloor$相等的时候,我们令$t=\lfloor \frac{n}{i} \rfloor$,左边界为l,右边界为r有:
$$c_n=a_t*\sum_{i=l}^{r}b_{n-t*i}$$
看了其他巨佬的做法了之后知道了要对b[]按位置的差值做一个前缀和
所以令f[i][j]表示位置差为j,当前位置为i的前缀和
然而空间开不下,所以j太大的时候暴力计算就好了(j大的时候显然减个几下就没了)
1 #include<bits/stdc++.h> 2 #define int long long 3 #define writeln(x) write(x),puts("") 4 #define writep(x) write(x),putchar(' ') 5 using namespace std; 6 inline int read(){ 7 int ans=0,f=1;char chr=getchar(); 8 while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} 9 while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 10 return ans*f; 11 }void write(int x){ 12 if(x<0) putchar('-'),x=-x; 13 if(x>9) write(x/10); 14 putchar(x%10+'0'); 15 }const int M = 1e5+5,mod = 123456789; 16 int a[M],b[M],n,m,s[M][205]; 17 inline int calc(int n,int x,int l,int r){ 18 int ans=0; 19 if(n/x<=200){ 20 if(l-n/x<0) ans=s[r][n/x]; 21 else ans=s[r][n/x]-s[l-n/x][n/x]; 22 ans=(ans%mod+mod)%mod; 23 }else{ 24 int y=n/(n/x); 25 for(int p=x;p<=y;p++)ans=(ans+b[n-p*(n/x)])%mod; 26 }return ans; 27 } 28 inline int Solve(int n){ 29 int ans=0; 30 for(int i=1,j,t;i<=n;i=j+1){ 31 if(n/i==0)j=n; 32 else j=n/(n/i); 33 t=a[n/i]*calc(n,i,n-j*(n/i),n-i*(n/i))%mod; 34 ans=(ans+t)%mod; 35 }return ans; 36 } 37 signed main(){ 38 n=read(); 39 for(int i=1;i<=n;i++)a[i]=read(); 40 for(int i=0;i<n;i++)b[i]=read(); 41 for(int i=0;i<n;i++) 42 for(int j=0;j<=200;j++) 43 if(i-j>=0)s[i][j]=(s[i-j][j]+b[i])%mod; 44 else s[i][j]=b[i]; 45 for(int i=1;i<=n;i++)printf("%lld\n",Solve(i)); 46 return 0; 47 }