cf1527 c Sequence Pair Weight
Posted yeah17981
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1527 c Sequence Pair Weight相关的知识,希望对你有一定的参考价值。
题目大意:给定一串序列,求出它所有子序列的贡献度之和
贡献度:某个字串{1,1,2,2,1}中相同数字的对数{i,j}(i<j,下同)
即{1,2} {3,4} {1,5} {2,5},贡献度为4
在t了十几发之后终于切了这题
题解来了:
找出一对{a[i],a[j]},则包含i……j的子串都能被这对{a[i],a[j]}所贡献,i前面有i-1个数字,j后面有n-j个数字,组合起来一共有i*(n-j+1)种情况是包含i……j的子串,这些字串都能提供一个贡献值
暴力:双层for求出每对{a[i],a[j]}的贡献值,求和
然后第一个T就来了
那在进行优化
我们得到了i*(n-j+1)这个式子,那么当j不变的时候,存在一个或多个i符合条件,则j在后面的所有贡献值为(i1+i2+……)*(n-j+1)
所以我们考虑用前缀和来维护,将j从后往前搜索,搜到后把前缀和-j然后找下一个j
前缀和要记录a[j],可是a[j]<=1e9,明显数组会爆
但是我们高兴的发现n只有1e5,这时候我们可以考虑离散化,大于1e5的最小质数是100003,自己创建一种规则来把这些数字塞到数组里
我们考虑建一个二维数组,第一排记离散化前的数字,第二排记前缀和
思路大致就完成了
下面是代码
#include<bits/stdc++.h>
using namespace std;
long long t[100005],k[100010][3];//t存序列,k是离散化
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(NULL);
long long n,a,i,z,y;
cin>>n;
while(n--)
{
cin>>a;
if(a==2)
{
for(i=1;i<=a;i++)
{
cin>>t[i];
}
if(t[1]==t[2]) cout<<1<<"\\n";
else cout<<0<<"\\n";
continue;
}
if(a==1)
{
cin>>t[1];
cout<<0<<"\\n";
continue;
}
memset(k,0,sizeof(k));
memset(t,0,sizeof(t));
y=0;
for(i=1;i<=a;i++)
{
z=0;
cin>>t[i];
if(t[i]<100003)
{
while(k[(t[i]+z)%100003][1]!=t[i]&&k[(t[i]+z)%100003][1]!=0)//离散化
{
z++;
}
k[(t[i]+z)%100003][1]=t[i];
k[(t[i]+z)%100003][2]+=i;
}
else
{
while(k[(t[i]%100003+z)%100003][1]!=t[i]&&k[(t[i]%100003+z)%100003][1]!=0)
{
z++;
}
k[(t[i]%100003+z)%100003][1]=t[i];
k[(t[i]%100003+z)%100003][2]+=i;//前缀和
}//离散化
}
for(i=a;i>=2;i--)
{
z=0;
while(k[(t[i]%100003+z)%100003][1]!=t[i])
{
z++;
}
if(k[(t[i]%100003+z)%100003][1]!=0&&k[(t[i]%100003+z)%100003][2]!=i)
{
y+= (k[(t[i]%100003+z)%100003][2]-i)*(a-i+1);
k[(t[i]%100003+z)%100003][2]=k[(t[i]%100003+z)%100003][2]-i;
}
}
cout<<y<<"\\n";
}
}
以上是关于cf1527 c Sequence Pair Weight的主要内容,如果未能解决你的问题,请参考以下文章
C - Sequence Pair Weight(组合数学)
Codeforces Round #721 (Div. 2)- C.Sequence Pair Weight - 双重前缀和累加