版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/91540609
题目
给定一个长度为 N 的序列 A1 A2 … An 和 Q 个询问,每次询问为求长度为 W 的子序列(连续)的权值和,定义一个序列的权值为该序列中不同元素的数的个数。
其中,0< W < = N <=10^ 6,0<=Q<=10^ 4,0<= A1 A2 … An <=10^ 6。
题解
我们设 表示长度为i的答案。
每一次的变化,就像这样:
区别就是每一组多了一个数组,少了最后的一组答案。
先考虑前者,我们考虑一下对于i来说它所加入的组是否会产生新答案:显然,要产生新答案必然需要满足和它一组的数每一个都和它不一样,即前面一个和它一样的数在这个组之前,设这个数的位置是x,当前数的位置为 ,组的大小为 ,必须满足 才能对答案做出贡献。
而我们需要计算每一个 ,有多少随 大于等于 ,我们用树状数组维护即可。
至于少的答案,也可以很方便的用线性方法简单的维护。
时间复杂度:
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n, cnt = 0;
int p[1000];
int c[2000000];
int d[2000000];
char a[2000000];
char b[2000000];
vector < int > tot[1000];
struct TREE {
int S[10000000] = {};
#define lowbit(i) (i & -i)
void add(int x,int v)
{
for (int i=x;i<=n;i+=lowbit(i))
S[i] += v;
return;
}
int ask(int x)
{
int sum = 0;
for (int i=x;i>=1;i-=lowbit(i))
sum += 1LL*S[i];
return sum;
}
} tree;
int main(void)
{
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
cin >> n;
cin >> a+1 >> b+1;
for (int i=1;i<=n;++i)
tot[b[i]-'A'].push_back(++cnt), d[i] = cnt;
for (int i=1;i<=n;++i)
{
int lt = a[i]-'A';
c[i] = tot[lt][p[lt]++];
}
long long ans = 0;
for (int i=n;i>=1;--i)
{
ans += (long long)tree.ask(c[i]);
tree.add(c[i],1);
}
cout<<ans<<endl;
return 0;
}