羅バレーP4071 [SDOI2016]配置数の説明

P4071 [SDOI2016]カウント配列

タイトル説明

どのように多くの系列Aの長さnを求め、以下の条件が満たされています:

この数n 1〜nは、各出現における配列

i番目のA [i]がIである場合、私が安定と呼ばれます。Mは、系列の数を正確に安定しています

多くの可能なシーケンスの条件を満たす、のシーケンス番号\(9 + 10 ^ 7 \)モジュロ。

入力形式

Tの数の最初の行、データのTセットが発現しました。

二つの整数N、Mの次Tライン。

出力フォーマット

T出力ライン、それぞれ得られた配列の数を表す数

サンプル入力と出力

入力#1

5
1 0
1
5 2
100 50
10000 5000

出力#1

0
1
20
578028887
60695423

説明/ヒント

。テストポイント〜3.1:T = 1000 $ \(\)。N- \のLeq 8 \(\)。m個の\ $のLeq 8。

〜テストポイント6 4:1000 = $ T \(\) N- \のLeq 12で\(\) M $ 12 \のLeqです。

テストポイント9〜7:1000 $ T =。。\(\) N- \のLeq 100 \(\) $ 100のLeq \ M。

テストポイント12〜10:T = 1000 $ \(\) N- \のLeq 1000 \(\) m個の\の$のLeq 1000;

テストポイント14〜13である:T = $ 500000 \(\) N- \のLeq 1000年\(\) m個の\の$のLeq 1000;

テストポイント20は、〜15:$ 500000 T = \(\) N- \のLeq 1000000 \(\) m個の\の$のLeq 1000000。

[思考]

組合せ数学/間違った行

[タイトル]効果

A [i]はI上方位置に安定している
シーケンス番号mを見つけるためには、安定した数であります

[解析]タイトル

必要な数は、配列が一致
見えるように安定させることができる配列の数と一致する
シーケンス番号mにのみ安定している
他の安定している
ナンバーワンであり、nはMの組み合わせの少ない安定した数
理由場合唯一の位置に対応する番号が安定
ようにいかなる順序は、存在しない前記\(C_N ^ Mの\)の
組み合わせの安定数を知っている
いくつかのための安定した数のこれらの組み合わせに加えを見てとること
であり、他の数値その上方位置にない
、すなわち千鳥
個々の方法の数の直接千鳥NMによって決定は(マイナス以下同様下に同じである)のようなスタッガード
数nm安定的個体千鳥の1つに対応するように
その数は数ある\(^ C_Nメートルの\)(nm)でソート個人の障害*

[問題点]

1.データ範囲ためにn及びmは以下1E6であり
、非常に小さい、及び大きいTはない、
ので、各T及びCは、全ての別個の放電の数が間違って行くことができない
、このタイムアウトをします
ので、この問題の2が撮影しましたモジュロ演算
要因の組み合わせの必要な数が不可避となるように組み合わせの数は、2000年を通して再帰見つけることができます
使用するために必要な分割することを
モジュロ演算は、除算器とすることができません

[最適化]

質問1 1.
繰り返して時間を解決する
ことが最初のiをソート前のすべての要因や個人的な障害を出てきた
ような、その時間O(1)クエリ
質問2 2.
私は、乗算除算でそれを使用することはできませんので、
と逆部門は、代わりにそれを使用することができます
モジュラスを反転するので素数である
ことが求めフェルマーの小定理を使用することができます
反転さはフェルマーの小定理を参照してください
ここに

[完了コード】

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int k = 1e9 + 7;
const int Max = 1000005;
int d[Max];
int f[Max];
int inv[Max];

int p(int a,int b)
{
    int ans = 1;
    while(b)
    {
        if(b & 1)
            ans = ans * a % k;
        b >>= 1;
        a = a * a % k;
    }
    return ans;
}

signed main()
{
    d[0] = 1,d[2] = 1;
    for(register int i = 3;i <= 1000000;++ i)
        d[i] = (i - 1) * (d[i - 1] + d[i - 2]) % k;
    f[0] = 1,f[1] = 1;
    for(register int i = 2;i <= 1000000;++ i)
        f[i] = f[i - 1] * i % k;
    inv[0] = p(f[0],k - 2);
    for(register int i = 1;i <= 1000000;++ i)
        inv[i] = p(f[i],k - 2) % k;
    int t;
    cin >> t;
    while(t --)
    {
        int n,m;
        scanf("%lld%lld",&n,&m);
        //c(n,m) * d(n-m)
        //n!/m!(n - m)! * d[n-m]
        printf("%lld\n",(f[n] * inv[m] % k * inv[n-m] % k * d[n-m]) % k);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/acioi/p/11736754.html