题解:[NOIP 2015 普及组] 求和
题意分析
对于三元组 \((x,y,z)\),显然其对于答案的贡献与 \(y\) 无关,因此可以考虑消去 \(y\)。\(y-x=z-y\) 即 \(x+z=2y\),也就是说 \(x,z\) 奇偶性相等。
\(\text{50pts}\)
\(\mathcal O(n^2)\) 枚举 \(x,z\),判断 \(color\) 值是否相等后统计答案即可。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100000,M=100000,P=10007;
int n,m,number[N+1],color[M+1];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",number+i);
}
for(int i=1;i<=n;i++){
scanf("%d",color+i);
}
int ans=0;
for(int l=1;l<=n;l++){
for(int r=l+2;r<=n;r+=2){
if(color[l]==color[r]){
ans=(ans+1ll*(l+r)*(number[l]+number[r]))%P;
}
}
}
printf("%d\n",ans);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
\(\text{90pts}\)
考虑对每一个格子按照颜色和奇偶性进行分类,枚举 \(x\) 的时候枚举 \(z\) 即可。
注意 \(x=z\) 时不要统计,同时会重复统计,答案需要除以 \(2\),模数 \(10007\) 为质数,使用逆元即可。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100000,M=100000,P=10007;
int n,m,number[N+1],color[M+1];
vector<int>a[M+1][2];
int qpow(int a,int n){
if(!n){
return 1;
}
int t=qpow(a,n>>1);
t=1ll*t*t%P;
if(n&1){
t=1ll*t*a%P;
}
return t;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",number+i);
}
for(int i=1;i<=n;i++){
scanf("%d",color+i);
a[color[i]][i&1].push_back(i);
}
int ans=0;
for(int l=1;l<=n;l++){
for(int r:a[color[l]][l&1]){
if(r==l){
continue;
}
ans=(ans+1ll*(l+r)*(number[l]+number[r]))%P;
}
}
printf("%d\n",1ll*ans*qpow(2,P-2)%P);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
\(\text{100pts TLE}\)
考虑在根据颜色、奇偶性分类后统计时先二分出 \(x\) 可行的 \(z\) 的左边界,减小常数。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100000,M=100000,P=10007;
int n,m,number[N+1],color[M+1];
vector<int>a[M+1][2];
int qpow(int a,int n){
if(!n){
return 1;
}
int t=qpow(a,n>>1);
t=1ll*t*t%P;
if(n&1){
t=1ll*t*a%P;
}
return t;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",number+i);
}
for(int i=1;i<=n;i++){
scanf("%d",color+i);
a[color[i]][i&1].push_back(i);
}
int ans=0;
for(int l=1;l<=n;l++){
int p=upper_bound(a[color[l]][l&1].begin(),a[color[l]][l&1].end(),l)-a[color[l]][l&1].begin();
for(int r=p;r<a[color[l]][l&1].size();r++){
ans=(ans+1ll*(l+a[color[l]][l&1][r])*(number[l]+number[a[color[l]][l&1][r]]))%P;
}
}
printf("%d\n",ans);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
\(\text{100pts AC}\)
考虑拆式子。
对于 \(x\),令 \(l,r\) 分别表示分类后数组 \(pl\) 中可行 \(z\) 的左右边界。
则 \(x\) 对于答案的贡献为:
\[\begin{aligned}
\sum_{i=l}^r[(x+pl_i)(number_x+number_{pl_i})]&=\sum_{i=l}^r[x\cdot number_x+x\cdot number_{pl_i}+pl_i\cdot number_x+pl_i\cdot number_{pl_i}]\\
&=(r-l+1)(x\cdot number_x)+x\sum_{i=l}^rnumber_{pl_i}+number_x\sum_{i=l}^rpl_i+\sum_{i=l}^rpl_i\cdot number_{pl_i}
\end{aligned}
\]
则对于每一个 \(pl\),处理出 \(number_{pl_i},pl_i,pl_i\cdot number_{pl_i}\) 的前缀和即可。
注意取模。
时间复杂度:\(\mathcal O(n\log n)\)。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100000,M=100000,P=10007;
int n,m,number[N+1],color[M+1];
struct node{
int i;
int numberSum,plSum,plNumberSum;
node(){
i=numberSum=plSum=plNumberSum=0;
}
};
bool operator <(const int &a,const node &b){
return a<b.i;
}
vector<node>a[M+1][2];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",number+i);
}
for(int i=1;i<=n;i++){
scanf("%d",color+i);
auto &pl=a[color[i]][i&1];
node x;
x.i=i;
if(pl.size()){
x.numberSum=pl.back().numberSum;
x.plSum=pl.back().plSum;
x.plNumberSum=pl.back().plNumberSum;
}
x.numberSum=(1ll*x.numberSum+number[i])%P;
x.plSum=(1ll*x.plSum+i)%P;
x.plNumberSum=(1ll*x.plNumberSum+1ll*i*number[i])%P;
pl.push_back(x);
}
int ans=0;
for(int x=1;x<=n;x++){
auto &pl=a[color[x]][x&1];
int l=upper_bound(pl.begin(),pl.end(),x)-pl.begin(),r=pl.size()-1;
int size=r-l+1;
ans=(ans+(1ll*size*x%P*number[x]%P+1ll*x*(pl[r].numberSum-pl[l-1].numberSum)%P+1ll*number[x]*(pl[r].plSum-pl[l-1].plSum)%P+1ll*(pl[r].plNumberSum-pl[l-1].plNumberSum)%P))%P;
}
printf("%d\n",(ans>0?ans:ans+P));
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号