wmq的队伍
时间限制: 2000ms 内存限制: 512M
交大上课需要打卡,于是在上课前的几分钟打卡机前往往会排起长队。
平时早睡早起早早打卡的wmq昨晚失眠,今天起晚了,于是他也加入了打卡队伍中。
这个时候,wmq发现了神奇的现象,打卡队伍可以按人们的身高看成一个队列,左边是队头,右边是队尾。
对于队列a1...an,wmq想知道其中存在多少的有序k元组l1...lk
使得1≤l1<l2<...<lk≤n,并且有al1>al2>...>alk
输入有多组数据
第一行是一个正整数T,1≤T≤15,代表数据组数
每组数据第一行是两个正整数n,k,1≤n≤2∗104,1≤k≤min(n,100)
n代表队列的人数,k 的含义见题面
接下来一行有n个正整数,代表1到n的一个排列,表示队伍的身高情况
对于每组数据,输出一个整数,代表有序k元组的个数
考虑到数字可能很大,将答案对109+7取模之后输出
复制
3 2 2 1 2 2 2 2 1 22 3 1 2 3 4 5 16 6 7 8 9 10 19 11 12 14 15 17 18 21 22 20 13
0 1 8
题解:定义C[i][j]为选了i个数 以小于等于j的数结尾的方案有多少
那么每次for到一个数 把它加到C[1][num]
然后第二层就是加上第一层所有结尾大于a[i]的方案数
第三层加上第二层。。。
这样递推下去
ans每次加上以a[i]结尾的方案数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll C[105][20005];
ll a[20005],b[20005],cnt;
void change(ll k,ll pos,ll x){
while(pos<=cnt){
C[k][pos]+=x;
C[k][pos]%=1000000007;
pos+=(pos&-pos);
}
}
ll sum(ll k,ll n){
ll ss=0;
while(n>0){
ss=(ss+C[k][n])%1000000007;
n-=(n&-n);
}
return ss;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
ll n,i,j,k;
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
cnt=unique(b+1,b+1+n)-b-1;
for(i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
for(i=0;i<=k;i++){
for(j=0;j<=cnt;j++)C[i][j]=0;
}
ll ans=0;
for(i=1;i<=n;i++){
change(1,a[i],1);
for(j=2;j<=k;j++){
change(j,a[i],sum(j-1,cnt)-sum(j-1,a[i]));
}
ans=((ans+sum(k,a[i])-sum(k,a[i]-1))%1000000007+1000000007)%1000000007;
}
cout<<ans<<endl;
}
return 0;
}

探讨了在特定条件下计算有序k元组数量的问题。通过分析队列中人们的身高顺序,利用离散数学与算法技巧,实现了高效求解方案。
192

被折叠的 条评论
为什么被折叠?



