解析
可以注意到 (k_i) 最多是 (100)。对于给定一段区间的某一段区间和,我们可以表示成两个前缀和的差,对于长度为 (len) 的给定区间,会有 (len+1) 个不同的前缀和(包括 (0),即什么都不取)。根据抽屉原理,当 (len>100) 的时候必然会有两个前缀和模 (k_i) 的结果是相同的,如果我们就选择这两个所表示的区间,显然结果就是 (k_i) 的倍数。于是,对于长度大于 (k_i) 的区间其实是一定存在的,而小于的,我们可以直接暴力枚举。
代码
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
namespace io {
inline LL read() {
LL x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') {
f=-1,c=getchar();
}
}
while(c>='0'&&c<='9') {
x=x*10+c-'0',c=getchar();
}
return x*f;
}
inline void write(LL x) {
char buf[40];
if(!x) {
putchar( '0' );
return ;
}
LL tmp=x>0?x:-x;
if(x<0) {
putchar('-');
}
LL cnt=0 ;
while(tmp>0) {
buf[cnt++]=tmp%10+'0',tmp/=10;
}
while(cnt>0) {
putchar(buf[--cnt]);
}
}
}
using namespace io;
const LL N=1e5+5;
LL a[N];
int main() {
LL t=read(),n=read();
for(LL i=1; i<=n; i++) {
a[i]=read()+a[i-1];
}
LL sum=0;
while(t--) {
LL l=read(),r=read(),k=read(),w=read();
if(r-l+1>k) {
sum+=w;
continue;
}
bool can=0;
for(LL i=l; i<=r; i++) {
for(LL j=i; j<=r; j++) {
if((a[j]-a[i-1])%k==0) {
can=1,sum+=w;
break;
}
}
if(can) {
break;
}
}
if(!can) {
sum-=w;
}
}
printf("%lld",sum+=read());
return 0;
}
感想
暴力出奇迹!