bzoj3157 国王奇遇记

%5:错误的以为可以搞死校园,结果%意义下是无法做到解唯一的,,于是就不会了
鬼畜式子好题+多项式黑科技:
%15:可以利用多项式或者dp,考虑dp的话,一般要构造一个式子然后互相推吧比较巧妙,有三种重要解法,分别是1,2维的dp和观察多项式特点
知识点:1.式子题构造然后dp 2.采用扰动法对指数或底数扰动,注意主要扰动上下界,做差 3.dp可以考虑倍增 4.一定要做题仔细,因为忽略了m=1这个点而调了很久很久(推倒时*(m-1),,事实证明我的程序一开始就没问题啊,,, 5.取模非常容易出问题,改变取模的习惯
%5:黑科技多项式,不会
%25:1.扰动法具体应用(两种)2.构造式子然后互相推倒的方法
%50:代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define N 200
using namespace std;
typedef long long ll;
ll n,m,c[N+5][N+5],x,f[N+5],P=1000000007,x1,x2;
ll pow_mul(ll a,ll b){
    ll r = 1, base = a;
    for (ll k = b; k ; k>>=1){
        if (k&1) r=r*base%P;
        base=base*base%P; 
    }
    return r;
}

void init(){
    cin>>n>>m;
    memset(c,0,sizeof(c));
    for (int i = 0; i <= N; ++i) c[i][0]=1; 
    for (int i = 1; i<= N; ++i)
      for (int j = 1; j <= i; ++j){
         c[i][j]=c[i-1][j]+c[i-1][j-1];
         if (c[i][j]>=P) c[i][j]-=P;
      }
    x1 = pow_mul(m - 1, P - 2);
    x2 = pow_mul(m , n + 1);
}

void dp(){
    ll d = n,flag;
    f[0] = (x2-m) * x1 % P;
    if (f[0]<0) f[0]+=P;
    //cout<<f[0]<<endl;
    for (int i = 1;i <= m; ++i){
      f[i]= x2 * d % P;
      d = d * n % P;
      for (int j = 0; j < i; ++j){
        flag=1;
        if ((i-j)%2==1) flag = -1; 
        f[i] = (f[i]+c[i][j]*flag*f[j]%P)%P;
        if (f[i]<0) f[i]+=P;
         }
      f[i] = f[i] * x1 % P;
    } 
}

void print(){
    if (m==1) cout<<n*(n+1)/2%P<<endl; 
    else cout<<f[m]<<endl;
    //for (int i=0; i<=m;++i) cout<<f[i]<<endl;
}

int main(){
   init();
   dp();
   print();
   return 0;
} 

你可能感兴趣的:(bzoj3157 国王奇遇记)