私は数学が苦手で、常に素数を法とする答えを必要とする問題に悩まされています。
例:(500!/ 20!)mod 1000000007
私はBigIntegersに精通していますが、(DPを使用した後でも)500の階乗を計算した後にモジュロを計算すると、負荷がかかるようです。
このような問題に対処する特定の方法があるかどうか知りたいのですが。
ここで私が現在解決しようとしているそのような問題の1つを示します。 http://www.codechef.com/FEB12/problems/WCOUNT
誰かが私にこれらのコーディングの問題を処理するためのチュートリアルまたはアプローチに導くことができれば、それは本当に役に立ちます。 JavaおよびC++に精通しています。
これらの多数のモジュラスタスクの鍵は、モジュラスを実行する前に完全な結果を計算することではありません。 数値を小さく保つために、中間ステップで係数を減らす必要があります:
500! / 20! = 21 * 22 * 23 * ... * 500
21 * 22 * 23 * 24 * 25 * 26 * 27 = 4475671200
4475671200 mod 1000000007 = 475671172
475671172 * 28 mod 1000000007 = 318792725
318792725 * 29 mod 1000000007 = 244988962
244988962 * 30 mod 1000000007 = 349668811
...
31768431 * 500 mod 1000000007 = 884215395
500! / 20! mod 1000000007 = 884215395
すべてのステップでモジュラスを減らす必要はありません。数値が大きくなりすぎないように、十分な頻度で実行してください。
long
の最大値は2 ^ 63-1であることに注意してください。したがって、2つの正の整数値(つまり、オペランドの1つがlong
)間で64ビット乗算を実行しても、オーバーフローしませんlong
。残りの操作を安全に実行できます%
その後(それが正の場合も同様)、必要に応じて整数にキャストバックします。
まず、500!/20!
は、21から500までのすべての数値の積です。次に、%1000000007
各操作の最後。これでプログラムを作成できるはずです。数値がオーバーフローしないように注意してください。32ビットでは不十分な場合があります。
これはあなたのために役立つと思います
for(mod=prime,res=1,i=20;i<501;i++)
{
res*=i; // an obvious step to be done
if(res>mod) // check if the number exceeds mod
res%=mod; // so as to avoid the modulo as it is costly operation
}