给定序列 ,求
计算所有区间和取模之后的结果再求和。
注意外层是没有取模的。
如果是外层也要取模的情况,那还是十分好办的,直接贡献法计算每个数字被统计了多少次就可以了。
问题就在于外层没有取模,之前好像也没有做过这种东西,于是就开始各种乱搞了,思路大概就是先算出不取模的结果,然后计算需要取模多少次,最后统一减去若干个 。
甚至还用上了 double 这种玩意。、、
转化题意, 的区间和,用前缀和来表达就是 ,这样就转化成了两点之差,所以我们要统计的就是所有的两点之差。
如果我们在做前缀和的时候就取模,那么 便有可能是负数, 但是注意到取模运算是乘法封闭的,是个负数的话 ,加上一个 就可以变成正确的值。
可以发现需要加上的 数,就是前缀和数组中的逆序对数量。
而 可以通过二位前缀和快速算出,注意要考虑 。
树状数组求逆序对还需要访问 的下标,所以树状数组的整体下标应该右移 。
| #include<bits/stdc++.h> |
| #define int long long |
| using namespace std; |
| template<typename T>inline void re(T &x) |
| { |
| x=0;int f=1;char c=getchar(); |
| while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} |
| while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} |
| x*=f; |
| } |
| const int N=4e5+10; |
| int c[N]; |
| int MOD,n; |
| inline void add(int x,int v) |
| { |
| for(;x<=MOD;x+=(x&-x))c[x]+=v; |
| } |
| inline int query(int x) |
| { |
| int ans=0; |
| for(;x>=1;x-=(x&-x))ans+=c[x]; |
| return ans; |
| } |
| int s[N],ss[N]; |
| signed main() |
| { |
| re(n),re(MOD); |
| for(int i=1;i<=n;++i) |
| { |
| re(s[i]); |
| s[i]+=s[i-1],s[i]%=MOD; |
| ss[i]=ss[i-1]+s[i]; |
| } |
| int cnt=0; |
| for(int i=n;i>=1;--i) |
| { |
| if(s[i]>0)cnt+=query(s[i]); |
| add(s[i]+1,1); |
| } |
| int ans=0; |
| for(int i=1;i<=n;++i) |
| ans+=i*s[i]-ss[i-1]; |
| cout<<ans+cnt*MOD; |
| return 0; |
| } |
求区间和可以转化成前缀和的差值,这样就简化了问题,变成了两点之差。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效