2019 计蒜之道 初赛 第三场 —— 母函数+欧拉降幂

91 篇文章 0 订阅

This way

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!} bk!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+ex)/2,那么构造的母函数也就变成 ( e x ) 2 ∗ ( ( e x + e − x ) / 2 ) 2 (e^x)^2*((e^x+e^{-x})/2)^2 (ex)2((ex+ex)/2)2,化简合并同类项之后就变成 e 4 x + 2 ∗ e 2 x + 1 4 \frac{e^{4x}+2*e^{2x}+1}{4} 4e4x+2e2x+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} 4n1+2n1
所以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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值