区间权值
时间限制: 1 Sec 内存限制: 128 MB
提交: 82 解决: 39
[提交] [状态] [讨论版] [命题人:admin]
题目描述
小Bo有n个正整数a1..an,以及一个权值序列w1…wn,现在他定义
现在他想知道的值,需要你来帮帮他
你只需要输出答案对+7取模后的值
输入
第一行一个正整数n
第二行n个正整数a1..an
第三行n个正整数w1..wn
1≤n≤3×
1≤ai≤
1≤wi≤
输出
输出答案对+7取模后的值
样例输入
3
1 1 1
1 1 1
样例输出
10
题解:
观察可知的意义为长度为r−l+1的所有区间的和与w[r−l+1]的乘积。
枚举ll、rr势必会超时,于是我们找一下规律。
以n=7n=7为例。
区间长度为1时,如下图所示:
每一条粗线表示每个元素被加的次数,也就是说,每个元素都被加了1次。
区间长度为2时,如下图所示:
第1、7个元素被加了1次,其余元素被加了2次。
区间长度为3时,如下图所示:
第1、7个元素被加了1次,第2、6个元素被加了2次,第3、4、5个元素被加了3次。
区间长度为4时,如下图所示:
第1、7个元素被加了1次,第2、6个元素被加了2次,第3、5个元素被加了3次,第四个元素被加了4次。
区间长度为5时,如下图所示:
第1、7个元素被加了1次,第2、6个元素被加了2次,第3、4、5个元素被加了3次。
区间长度为6时,如下图所示:
第1、7个元素被加了1次,其余元素被加了2次。
区间长度为7时,如下图所示:
每个元素都被加了1次。
显然可以发现长度为l和n-l的权值相同,然后枚举每个长度l,发现出现次数为两端向中间增加,然后中间不变,最后O(n)扫一遍即可
因为两边对称所以求出一边乘上不同的权值即可
tmp表示前缀和 所以是+=
tmp * w[i]表示 前半部分的值
tmp * w[n - i + 1]表示 后半部分的值
最后n为奇数特判一下中间的值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (int)3e5 + 10;
const ll MOD = 1e9 + 7;
int n;
ll ans;
ll w[maxn];
ll val[maxn];
int main()
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; ++i)
{
scanf("%lld", val + i);
}
for(int i = 1; i <= n; ++i)
{
scanf("%lld", w + i);
}
for(int i = 1; i <= n; ++i)
{
val[i] += val[i - 1];
val[i] %= MOD;
}
ans = 0;
ll tmp = 0;
for(int i = 1; i <= n / 2; ++i)
{
tmp += (val[n - i + 1] - val[i - 1] + MOD) % MOD;
tmp %= MOD;
ans += (tmp * w[i] % MOD + tmp * w[n - i + 1] % MOD) % MOD;
ans %= MOD;
}
if(n & 1)
{
tmp += val[(n + 1) / 2] - val[n / 2];
tmp %= MOD;
ans += tmp * w[(n + 1) / 2] % MOD;
ans %= MOD;
}
printf("%lld\n", ans);
}
return 0;
}
s[i]表示a[i]的前缀和
c[i]表示正向的计算次数的前缀和
nic[i]表示反向的计算次数的前缀和
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fll
#define pi acos(-1.0)
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
ll qpow(ll x, ll y, ll mod){ll s=1;while(y){if(y&1)s=s*x%mod;x=x*x%mod;y>>=1;}return s%mod;}
//ll qpow(ll a, ll b){ll s=1;while(b>0){if(b%2==1)s=s*a;a=a*a;b=b>>1;}return s;
const int mod = 1e9+7;
const int maxn = 3e5+5;
int n;
ll ans, tmp;
ll a[maxn],w[maxn];
ll s[maxn],c[maxn],nic[maxn];
int main()
{
ans = 0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
s[i] = (s[i-1]+a[i])%mod;
c[i] = (a[i]*i%mod + c[i-1])%mod;
}
for(int i=n;i>=1;i--)
nic[i] = (nic[i+1]+a[i]*(n-i+1)%mod)%mod;
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
/*
ll ans1 = 0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ans1 = ans1 + (s[j]-s[i-1])*w[j-i+1];
}
}printf("%lld--*--",ans1);
*/
for(int i=1;i<=n;i++)
{
if(i-1<=n-i+1)
tmp = (c[i-1]+nic[n-i+1+1]+(s[n-i+1]-s[i-1]+mod)%mod*i%mod)%mod;
else
tmp = (c[n-i]+nic[i+1]+(s[i]-s[n-i]+mod)%mod*(n-i+1)%mod)%mod;
ans = (ans+tmp*w[i]%mod)%mod;
}
printf("%lld\n",ans);
//return main();
return 0;
}
纯暴力
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fll
#define pi acos(-1.0)
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
ll qpow(ll x, ll y, ll mod){ll s=1;while(y){if(y&1)s=s*x%mod;x=x*x%mod;y>>=1;}return s%mod;}
//ll qpow(ll a, ll b){ll s=1;while(b>0){if(b%2==1)s=s*a;a=a*a;b=b>>1;}return s;
const int mod = 1e9+7;
const int maxn = 3e5+5;
int n;
ll ans, tmp;
ll a[maxn],w[maxn];
ll s[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
s[i] = (s[i-1]+a[i])%mod;
}
ll ans1 = 0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ans1 = ans1 + (s[j]-s[i-1])*w[j-i+1];
}
}
printf("%lld\n",ans1);
//return main();
return 0;
}