qbxt Day 2 数论 +DP +DP

来源:互联网 发布:数控车床车圆弧编程 编辑:程序博客网 时间:2024/05/21 18:45

T1

这里写图片描述

exgcd求逆元,化除为乘,因为除法不支持分配律;
时间 : O(log mod) ;

对于 (1/a) mod p;
求得a %p意义下 的逆元x,在模运算中可以替代1/a,相当于倒数(x并不一定等于倒数,只是
在取模的意义下与倒数发挥作用相同);

逆元为积性函数;

逆元x可能为负数,所以要 ( x%mod + mod ) % mod;

注意开long long;

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const ll MAXN=300001,mod=1000000007;ll inv,fac[MAXN],n,m,y,ans,t;void exgcd(ll a,ll b,ll &x,ll &y){    if(!b) {x=1,y=0;return;}    exgcd(b,a%b,x,y);    t=x,x=y,y=t-(a/b)*y;    return;}void solve(){    scanf("%lld%lld",&n,&m);    fac[0]=1;    for(ll i=1;i<=n;i++) fac[i]=(fac[i-1] % mod * i % mod) % mod;    exgcd(fac[m],mod,inv,y);    inv=(inv % mod + mod) % mod;    ans=inv%mod;    inv=y=0;    exgcd(fac[n-m],mod,inv,y);    inv=(inv % mod + mod)% mod ;    ans=(ans * (inv %mod) ) %mod;    cout<<(fac[n] % mod * ans % mod) % mod;    return;}int main(){    solve();    return 0;}

费马小定理:

逆元利器;
假如p是质数, 且 gcd (a,p) = 1,那么 a ^ (p-1) ≡ 1(mod p)

则 a^(p-2)是 a%p意义下的逆元;

初始化;

注意 1的逆元为1

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const ll MAXN=300001,mod=1000000007;ll fac[MAXN],inv[MAXN],n,m;ll ksm(ll a,ll b){    ll tot=1;    while(b)    {        if(b & 1) tot=(tot*a)%mod;        a=(a*a)%mod;        b>>=1;    }    return tot%mod;}void solve(){    cin>>n>>m;    fac[0]=1,inv[0]=1;    for(int i=1;i<=n;i++)    {        fac[i]=fac[i-1] * i %mod;        inv[i]=ksm(fac[i],mod-2)%mod;    }    cout<<(inv[m] %mod * inv[n-m] %mod * fac[n])%mod;    return;}int main(){    solve();    return 0;}

T2

这里写图片描述

调了一中午精度,最后也没调来,先弃了;

吐槽:
标程的状态转移不对;

题外话:
改了码风,好看了不少233;

思路:
dp[i][j]:前i个袋子中有j个袋子选到以1开头的球;

由于i只从i-1转移而来;
所以滚动数组优化;

注意:
用前缀和记录 以1打头的数,再计算;
第40行记录答案时,为了防止精度被卡,可以扩大后再枚举;

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;typedef double ld;const ll MAXN=2001;ld dp[MAXN],p[MAXN],ans;ll n,k;ll getsum(ll num){    if(!num) return 0;    ll now = 1,sum = 1;    if(num < 10) return sum;    for(ll i = 1;i <= 19;i ++)    {        now *= 10;        if(now > num) return sum;        else if(now*2 > num) return num-now+sum+1;        sum+=now;    }}void solve(){    scanf("%d%d",&n,&k);    dp[0]=1;    for(int i=1;i<=n;i++)    {        int l,r;        scanf("%d%d",&l,&r);        ld p=(ld)((ld)(getsum(r) - (ld)getsum(l - 1)) / (ld)(r - l + 1));        for(int j = i; ~j ;j --) dp[j] = dp[j-1] * p + dp[j] * (1 - p);    }    for(int i = n ; i *100>= n * k; i --) ans += (ld)dp[i];    printf("%.7f",ans);    return;}int main(){    solve();    return 0;}

T3

这里写图片描述

暂时弃掉~