[分块]JZOJ 100035 区间
分析
这题赛场打的是部分分,逆元前缀乘积40points
然后比赛结束看题解发现自己最早的想法已经接近正解了(fk u)
一开始是想分块,维护区间乘积,然后空间和时间都不接受
其实只需要维护块内前缀乘积和后缀乘积即可,这样可以O(1)得到乘积并异或上去
#include <iostream> #include <cstdio> using namespace std; const int N=10000001; int s[2*N]; int sumq[2*N],sumn[2*N]; int n,k,m,P,a,b,c,d; void Block(int x) { int l=(x-1)*k+1,r=min(x*k,n); sumq[l]=s[l];sumn[r]=s[r]; for (int i=l+1;i<=r;i++) sumq[i]=1ll*sumq[i-1]*s[i]%P; for (int i=r-1;i>=l;i--) sumn[i]=1ll*sumn[i+1]*s[i]%P; } int main() { freopen("range.in","r",stdin); freopen("range.out","w",stdout); scanf("%d%d%d",&n,&k,&P); scanf("%d%d%d%d",&a,&b,&c,&d); s[1]=a; for (int i=2;i<=n;i++) s[i]=(1ll*s[i-1]*b+c)%d; int m=n/k; if (m*k<n) m++; for (int i=1;i<=m;i++) Block(i); long long ans=0; for (int i=1;i<=n-k+1;i++) { int sum=1; if (!((i-1)%k)) sum=sumq[min(i+k-1,n)]; else sum=1ll*sumn[i]*sumq[min(i+k-1,n)]%P; ans^=1ll*sum; } printf("%lld",ans); fclose(stdin);fclose(stdout); }
在日渐沉没的世界里,我发现了你。