小魂和他的数列
题目大意
给出一个数列,让求长度为k的严格递增子序列有多少个
怎么做呢?
显然dp 这个是很好想的
for (int i= 1; i <= n; i ++ )
{
dp[i][1] =1;
}
for (int i = 2; i <= m; i ++ )
{
for(int j = i; j <= n; j ++ )
{
for (int k = 1; k < j; k ++ )
{
if(a[k] < a[j])
{
dp[j][i] += dp[k][i-1];
}
}
}
}
这个dp显然tle 所以 当时没有做出来。 做到这里不会做了。。
想不到怎么优化。
显然在最里面的那个循环的作用是前缀和 (小于a[i]的位置的dp的前缀和)
于是你得想到树状数组优化。。 我太菜了想不到
开k个树状数组优化最里面的那一层循环
于是就得到先离散化再根据他的值加进去 再求前缀和加到dp里的操作
于是就写了个这个:
for (int i = 1; i <= n; i ++ )
{
vis[i] = lower_bound(vv.begin(),vv.end(),a[i]) - vv.begin() + 1;
}
l = vv.size();
for (int i= 1; i <= n; i ++ )
{
dp[i][1] =1;
}
for(int i = 2; i <= m; i ++ )
{
for (int j = 1; j <= n; j ++ )
{
add(vis[j],i - 1,dp[j][i-1]);
dp[j][i] = (dp[j][i] + query(vis[j] - 1,i - 1))%mod;
}
}
本来只能过60% 加个vis数组预处理了一下离散化后的值
能过85%
可是这又不是他妈的oi赛制
还是a不了
于是参考了大佬博客了。。。
地址
代码:
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int mod = 998244353;
const int maxn = 5e5+5;
int a[maxn];
int dp[maxn][11];
int tree[maxn][11];
int l;
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int f,int num)
{
while( x <= l )
{
tree[x][f] = (tree[x][f] + num) % mod;
x += lowbit(x);
}
}
int query(int x,int f)
{
int ans = 0;
while(x > 0)
{
ans = (ans + tree[x][f])%mod;
x -= lowbit(x);
}
return ans;
}
vector<int> vv;
int num[maxn];
int vis[maxn];
int temp[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++ )
{
scanf("%d",&a[i]);
vv.push_back(a[i]);
}
sort(vv.begin(),vv.end());
vv.erase(unique(vv.begin(),vv.end()),vv.end());
for (int i = 1; i <= n; i ++ )
{
vis[i] = lower_bound(vv.begin(),vv.end(),a[i]) - vv.begin() + 1;
}
l = vv.size();``
for (int i = 1; i <= n; i ++ )
{
num[vis[i]] ++ ;
dp[vis[i]][1] = num[vis[i]];
add(vis[i],1,1);
for (int j = 2; j <= m; j ++ )
{
temp[j] = query(vis[i] - 1,j - 1);
dp[vis[i]][j] = (dp[vis[i]][j] + temp[j])%mod;
}
for (int j = 2; j <= m; j ++ )
{
add(vis[i],j,temp[j]);
}
}
int ans = 0;
for (int i =1; i <= n ; i++ )
{
ans =(ans + dp[i][m]) %mod;
}
printf("%d\n",ans%mod);
}