[蓝桥杯][2017年第八届真题]k倍区间
暴力的做法是O(n2),枚举左右端点l和r,通过前缀和计算出sum[l∼r]=sum[r]−sum[l−1],但不足以通过此题。
题意可转化为:找两个端点l和r,使得sum[l∼r]%k=(sum[r]−sum[l−1])%k==0,即sum[r] \equiv sum[l-1] \mod k。
于是我们统计出所有sum[i] \mod k的余数,记为cnt[sum[i]\%k]。
最后枚举余数(0 \sim k-1),假设当前枚举的余数为m,则满足sum[l \sim r]\%k == m的l和r配对的个数为C_{cnt[m]}^2。
注意点
由于sum[0]=0,因此初始时cnt[0]=1。
const int N=1e5+10; LL sum[N],cnt[N]; int n,k; int main() { cin>>n>>k; cnt[0]=1; for(int i=1;i<=n;i++) { cin>>sum[i]; sum[i]+=sum[i-1]; cnt[sum[i]%k]++; } LL ans=0; for(int i=0;i<k;i++) { ans+=cnt[i]*(cnt[i]-1)/2; } cout<<ans<<endl; //system("pause"); return 0; }
也可以采用下面更简洁的写法,不再是求组合数了,而是规定了一个顺序,每次求当前为右端点r的情况下,1 \sim i-1中与sum[r]同余模k的左端点l的个数。
const int N=1e5+10; int sum[N],cnt[N]; int n,k; int main() { cin>>n>>k; LL ans=0; cnt[0]=1; for(int i=1;i<=n;i++) { cin>>sum[i]; sum[i]=(sum[i]+sum[i-1])%k; ans+=cnt[sum[i]]; cnt[sum[i]]++; } cout<<ans<<endl; //system("pause"); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
· 用 C# 插值字符串处理器写一个 sscanf