P3131 [USACO16JAN] Subsequences Summing to Sevens S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目大意 求出一个区间 使得区间内的数字和对七取余等于0 输出该区间长度
一开始我是直接前缀和 +暴力做的
两层嵌套时间复杂度n^2 有一个点过不去 只拿了80
#include<iostream>
using namespace std;
const int N=50050;
int a[N];
int s[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]+=s[i-1]+a[i];
}
int mask=0;
int maxx=0;
for(int j=n;j>0;j--){
for(int i=0;j-i+1>=maxx;i++){
if((s[j]-s[i-1])%7==0){
maxx=max(maxx,(j-i+1));
mask=1;
break;
}
}
}
if(mask==1){
cout<<maxx;
}
if(mask==0){
cout<<0;
}
return 0;
}
然后是人殇物已非 的个人中心 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
大佬的思路
首先
我们将前缀和区间和s[r],s[l-1]分别用a,b表示
如果(a-b)mod7=0则a mod 7- b mod 7=0,所以a mod 7=b mod 7;
所以我们对前缀和进行预处理将它变成mod 7 的余数
然后扫描整个余数数组 找出长度最长的两端点余数相同的区间即可
这里两端相同余数 夹的最长区间长度是1号和6号的两个余数3。
从前往后扫和从后往前扫 找出每个余数的最晚出现位置和最早出现位置
for(int i=0;i<=n;i++){
last[s[i]]=i;
}
for(int j=n;j>=0;j--){
pre[s[j]]=j;
}
完整代码
#include<iostream>
using namespace std;
const int N=50050;
int a[N];
int s[N];
int pre[N],last[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]+=(s[i-1]+a[i])%7;
}
for(int i=0;i<=n;i++){
last[s[i]]=i;
}
for(int j=n;j>=0;j--){
pre[s[j]]=j;
}
int maxx=0;
for(int i=0;i<=6;i++){
maxx=max(maxx,last[i]-pre[i]);
}
cout<<maxx;//如果没有符合条件区间 maxx不会被修改 直接输出0
return 0;
}