题目描述
有一个长为 的数组,它是由长为 的数组 重复 次得到的。
定义这个数组的一个区间的权值为它里面不同的数的个数,现在,你需要求出对于这个数组的每个非空区间的权值之和。
答案对 取模。
输入格式
从 loop.in 中读入数据。
第一行两个整数 和 。
接下来一行 个整数,第 个整数为 。
输出格式
输出答案到 loop.out 中。
输出一个整数,表示答案。
样例
样例输入
2 2
1 2
样例输出
16
数据范围与提示
思路
对于本题,可以知道一个数字对答案的贡献是包含这个数字的区间的个数
这个问题比较难求,所以将它转换为总区间个数 – 不包含这个数的区间个数
剩下的看标 ~ _ ~
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#define re register
#define LL long long
#define INF 100000009
using namespace std;
const LL N=1e6+100,M=2020,mod=1e9+7;
vector < int > q[N];
struct sb { LL wz,ans; } b[N];
LL n,m,gs,ans,sb1,sb2,maxn,a[N],c[N],k[N],f[N],last[N];
bool cmp_1 ( sb a,sb b ) { return a.ans<b.ans; }
bool cmp_2 ( sb a,sb b ) { return a.wz<b.wz; }
void lsh ( ) // 离散化
{
LL cnm=0;
for ( LL i=1;i<=n;i++ ) b[i].ans=a[i],b[i].wz=i;
sort ( b+1,b+1+n,cmp_1 );
for ( LL i=1;i<=n;i++ )
{
if ( b[i].ans==b[i-1].ans ) c[i]=cnm;
else c[i]=++cnm;
}
for ( LL i=1;i<=n;i++ ) b[i].ans=c[i];
sort ( b+1,b+1+n,cmp_2 );
for ( LL i=1;i<=n;i++ ) a[i]=b[i].ans;
gs=cnm;
}
LL change ( LL n ) { return ( n+1 )*n/2%mod; } // 等差数列求区间个数
int main ( )
{
// freopen ( "loop.in","r",stdin );
// freopen ( "loop.out","w",stdout );
scanf ( "%lld %lld",&n,&m );
for ( LL i=1;i<=n;i++ ) scanf ( "%lld",&a[i] );
lsh ( );
for ( LL i=1;i<=n;i++ ) q[a[i]].push_back ( i ); // 看每个数在数组中的位置
for ( LL i=1;i<=gs;i++ )
{
LL len=q[i].size ( );
for ( int j=1;j<len;j++ ) ans=( ans+change ( q[i][j]-q[i][j-1]-1 )*m%mod )%mod;
// 求在 1 ~ n 中每两个相同的数之间区间的个数,在对于每个数相应 * k
ans=( ans+change ( q[i][0]-1 )+change ( n-q[i][len-1] )+change ( q[i][0]-1+n-q[i][len-1] )*( m-1 )%mod )%mod;
// 求在 1 ~ n 中这个数第一次出现的位置之前再加最后一个数之后的这两段区间并起来的区间个数在 * ( k-1 )
// 再加上最前面和最后面的区间个数
}
// printf ( "%d\n",ans );
printf ( "%lld",( change ( n*m%mod )*gs%mod+mod-ans )%mod );
//最后在用所有的可能减去 ans
return 0;
}