NC17065-子序列-(数学+dp)
https://ac.nowcoder.com/acm/problem/17065
题意:有n个数的数组a,求数组的子序列个数,满足子序列 { ap1,ap2,...apm },p1<p2...<pm,使得子序列中的任意两个数满足aij < aji (i<j)。结果对1e9+7求模。
思路:看起来吓死人,对不等式一步步化简。
aij < aji
→ log aij < log aji
→ j*log ai < i*log aj
→ (log ai)/i < (log aj)/j
对于每一个数ai可以处理出一个(log ai)/i的数,姑且叫做bi,这就变成了b数组的递增子序列问题,dp[i]表示以bi结尾的子序列的个数,从样例数据可以知道每一个数本身就是一个子序列,dp[i]要初始化为1。对每一个bi,寻找前面比它小的递增子序列个数与自己 再构成递增子序列。时间复杂度O(n2)。
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; const ll p=1e9+7; int n; double b[105]; double c[105];///树状数组 ll dp[105];///以i结尾的符合要求的子序列有多少个 int main()///NC17065子序列 数论+dp { scanf("%d",&n); for(int i=1;i<=n;i++) { double x; scanf("%lf",&x); b[i]=log(x)/(double)i; dp[i]=1; } ll ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(b[j]<b[i]) dp[i]=(dp[i]+dp[j])%p; } ans=(ans+dp[i])%p; } printf("%lld\n",ans); return 0; }