A淘宝商品价格大PK
题意:
给你n个数,假设这些数的最长上升子序列长度为len,问你有多少种情况使得去掉其中某一个数这些数的最长上升子序列长度小于len。
题解:
对于n只有100的情况我们只需要先做出它的最长上升子序列,之后再枚举删掉每一个数的情况,再暴力做,由于我也懒得用优化的dp,所以时间复杂度是 O ( n 3 ) O(n^3) O(n3)。注意其中的数是可能=0的。
#include<bits/stdc++.h>
using namespace std;
int a[105],arr[105];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int mx=1;
arr[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>arr[mx])
arr[++mx]=a[i];
for(int j=1;j<=mx;j++)
{
if(a[i]<=arr[j])
{
arr[j]=a[i];
break;
}
}
}
int k,ans=0;
for(int flag=1;flag<=n;flag++)
{
memset(arr,0,sizeof(arr));
k=1;
arr[1]=flag==1?a[2]:a[1];
for(int i=flag==1?3:2;i<=n;i++)
{
if(i==flag)
continue;
if(a[i]>arr[k])
arr[++k]=a[i];
for(int j=1;j<=k;j++)
{
if(a[i]<=arr[j])
{
arr[j]=a[i];
break;
}
}
}
if(k<mx)
ans++;
}
printf("%d\n",ans);
return 0;
}
B,C,D阿里巴巴协助征战SARS
B能用递推来解决,但是C和D就不行了,这里引入母函数的概念。
这里使用的母函数是指数型母函数,也就是解决有多少种放法的问题,对于有2个数,第一个数有a1个,第二个数有a2个的情况,那么构造的母函数就是以下的形式:
(
1
+
x
+
x
2
2
!
+
.
.
.
+
x
a
1
a
1
!
)
∗
(
1
+
x
+
x
2
2
!
+
.
.
.
+
x
a
2
a
2
!
)
(1+x+\frac{x^2}{2!}+...+\frac{x^{a1}}{a1!})*(1+x+\frac{x^2}{2!}+...+\frac{x^{a2}}{a2!})
(1+x+2!x2+...+a1!xa1)∗(1+x+2!x2+...+a2!xa2),注意这里的除上阶乘并不是你要确实的去除它,而是一种形式,在最后做完的时候
a
i
!
ai!
ai!依旧当成分母,而你所需要的第k项的系数,也就是
b
∗
x
k
k
!
b*\frac{x^k}{k!}
b∗k!xk的b就是答案。
对于这一道题没有数量的限制,但是有出现次数的限制,所以构造出来的母函数也就是
(
1
+
x
2
2
!
+
.
.
.
+
x
n
n
!
)
2
∗
(
1
+
x
+
x
2
2
!
+
.
.
.
+
x
n
n
!
)
2
(1+\frac{x^2}{2!}+...+\frac{x^{n}}{n!})^2*(1+x+\frac{x^2}{2!}+...+\frac{x^{n}}{n!})^2
(1+2!x2+...+n!xn)2∗(1+x+2!x2+...+n!xn)2,A和C是前面那一种母函数,B和D是后面那一种。为了简化问题,我们知道
e
x
e^x
ex的泰勒展开式为
1
+
x
+
x
2
2
!
+
.
.
.
1+x+\frac{x^2}{2!}+...
1+x+2!x2+...,而对于只有偶数项的式子来说,也就相当于
(
e
x
+
e
−
x
)
/
2
(e^x+e^{-x})/2
(ex+e−x)/2,那么构造的母函数也就变成
(
e
x
)
2
∗
(
(
e
x
+
e
−
x
)
/
2
)
2
(e^x)^2*((e^x+e^{-x})/2)^2
(ex)2∗((ex+e−x)/2)2,化简合并同类项之后就变成
e
4
x
+
2
∗
e
2
x
+
1
4
\frac{e^{4x}+2*e^{2x}+1}{4}
4e4x+2∗e2x+1。
已知
e
4
x
e^{4x}
e4x的第n项的系数为
4
n
,
e
2
x
4^n,e^{2x}
4n,e2x第n项的系数为2^n,代到上面那个式子中就变成
4
n
−
1
+
2
n
−
1
4^{n-1}+2^{n-1}
4n−1+2n−1。
所以B题和C题可以用快速幂来做,但是D题的数据范围过大,如果用C++无法保存那么大的数据,怎么办?这时候就需要用到一个东西叫做欧拉降幂,什么是欧拉降幂,就是一个公式:
x
n
%
m
o
d
=
x
(
n
)
%
φ
(
m
o
d
)
+
φ
(
m
o
d
)
%
m
o
d
,
φ
(
x
)
x^n\%mod=x^{(n)\%φ(mod)+φ(mod)}\%mod,φ(x)
xn%mod=x(n)%φ(mod)+φ(mod)%mod,φ(x)是欧拉函数表示从1到x与x互质的数的个数。这样就可以处理输入了,然后就40分钟快乐AK。
#include<bits/stdc++.h>
#define ll long long
const ll mod=1e9+7,pmod=1e9+6;
ll qpow(ll a,ll b)
{
ll ans=1,ret=a;
while(b)
{
if(b&1)
ans=ans*ret%mod;
ret=ret*ret%mod;
b>>=1;
}
return ans;
}
ll a[100005];
char s[100005];
int main()
{
ll n,x;
while(scanf("%s",s+1)){
if(s[1]=='0')
break;
int len=strlen(s+1);
n=0;
for(int i=1;i<=len;i++)
{
x=s[i]-'0';
n=(n*10+x)%pmod;
}
ll z=(qpow(4,(n-1+pmod)%pmod+pmod)+qpow(2,(n-1+pmod)%pmod+pmod))%mod;
printf("%lld\n",z);
}
return 0;
}