[cf 1097D] D。誠と黒板

質問の意味:正の整数nを与え、k個の操作があり、各操作nをnの係数で除算します(1-nは可能です)、いずれかで除算する確率は同じです。最後に残っている数の数学を見つけます期待します。(1 <= n <= 10 ^ 15,1 <=)

範囲:分割して征服する、逆元、dp(法を見つける?)
注:元のポスターは正しい考え方を保証することはできません、私を助けることができれば、いくつかの不正が許されていることを大男が見てくれることを願っています、
アイデアをありがとう:最初に質問の意味を読んでください、ドラフトペーパーでシミュレーションし、データ範囲、wocの問題点を確認して、シャットダウンを開始しました。

それがゲーム中に使われた方法です。


家の近く(ため息)、この質問をどのように書くのですか?まず、要因と関係があります。次に、この角度から始めます。すべてを同時に考慮すると、間違いなく爆発します。主要な要因が1つしかない状況を検討する必要があります。
例2:i [] = 1 2 4 8;
明らかに、各数値の因子の数は、数値m = log2(i [a])+ 1以下の数値の数に等しく、各操作の後、元のこの値の確率はj [a]であり、各係数はj [a] / mに割り当てられます。

次に、分割の数によって引き起こされる影響を見てください。

1 2 4 8
1 j [1]
2 j [2] / 2 j [2] / 2
4 j [3] / 3 j [3] / 3 j [3] / 3
8 j [4] / 4 j [4] / 4 j [4] / 4 j [4] / 4

横の行は各古い値が各新しい値に与える影響を表し、縦の行は各新しい値と各値を表します。各値を合計する場合は、以下の合計レコードを使用して新しい値を取得します。
この表から、プライムファクターが1つしかない場合に、各分割後の値の変化を推測できます。プレフィックスとバックツーフロントの最適化を使用すると、時間の複雑さは許容範囲内になります。

これは単なる主要な要因なので、複数のものをプッシュしましょう(以下は不完全に正しく、音声構成が不十分な場合があります)

別の例を挙げましょう。12。最初の操作では、数のすべての要素が等しい確率であることがわかります。すべて1であると仮定します。計算の便宜上、すべての確率に分母の最小の一般的な倍数を掛けます。次の表を取得できます。

1 2 3 4 6 12
1 12
2 6 6
3 6 6
4 4 4 4
6 3 3 3 3
12 2 2 2 2 2 2

あなたは推測を試みることができます、ただ1つのプライムファクターからの結果は複数のプライムファクターと関係がありますか?
1 2 4のデータを見るだけで、単一のプライムファクターと一致します。
次に、それは2つの部分に分割されます:{1,2,4}、{3,6,12}。
ここに写真の説明を挿入
上の写真から、青い部分は赤い部分の2倍です。2倍の理由は、上のi [a]の要素の数が3i [a]の半分、3 i [a]の半分が赤、半分が黒。
ここに写真の説明を挿入
垂直方向では、この写真の非青色はそれぞれ上部の青色の1/2です。水平方向では、同じ色が同じ値になります。

{1,2,4}と{3,6,12}は3:1の関係にあると計算できます(プライムファクターは1つだけで、プライムファクターの数は1、操作の数は2です)。
なぜそれは3:1でなければならないのですか?上記は証明されています。
なぜ3:1が表示されるのですか?プライムファクター3の発生数は1であるため、操作の数は2です。
2回以上の発生回数は合っていますか?はい、読者は自分で推測することができます。手順は上の2つの写真に示されているとおりです(最初の写真の青と赤の部分に注意を払う必要がある場合があります)。
したがって、res(n、m)を答えとし、timを係数pがnに含まれる回数とすると、res(n * p、m)= res(n、m)* res(p ^(tim + 1)、m) / res(p ^ tim、m)。この式から、答えはこの主要な要因に関連する結果にのみ影響されることがわかります。それを整理するために、各因子は単一の因子に対して別々に計算され、次に結果を得るために乗算されます。

単一の要因の影響は前処理できますが、主要な要因の総数がデータ範囲内にあまりないため、前処理しないことの影響は大きくありません。

コードは次のように表示されます。

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 5;
const ll Mod = 1e9 + 7;

int inv[maxn];
void invers(int o)
{
	inv[1] = 1;
	for(int oo = 2;oo <= o;oo ++)
	{
		inv[oo] = (long long)(Mod - Mod / oo) * inv[Mod % oo] % Mod;
	}
}

ll ce(ll o,ll onum,ll kk)
{
	ll arr[onum + 1][2],o1=0,o2=1;
	arr[onum][0] = 1;
	for(ll pp = 0;pp < onum;pp ++) arr[pp][0] = 0;
	for(ll pp = 1;pp <= kk;pp ++)
	{
		for(ll oo = onum;oo >= 0;oo --)
		{
			arr[oo][o2] = arr[oo][o1] * inv[oo + 1] % Mod;
			if(oo != onum)  arr[oo][o2] = (arr[oo][o2] + arr[oo+1][o2]) % Mod;
		}
		swap(o1,o2);
	}
	
	ll p = 1; 
	ll ress = arr[0][o1];
	for(ll oo = 1;oo <= onum;oo ++)
	{
		p = p * o % Mod;
		ress = (ress + arr[oo][o1] * p % Mod) % Mod;	
	}

	return ress;
}
	ll n,k,a,res;
	
int main()
{
	scanf("%I64d%I64d",&n,&k);
	invers(100000);
	res = 1;
	for(a = 2;a * a <= n;a ++)
		if(n % a == 0)
		{
			int anum = 0;
			while(n % a == 0)
			{
				anum ++;
				n /= a;
			}
			if(anum != 0)
				res = res * ce(a,anum,k) % Mod;	
		}
	if(n != 1)
		res = res * ce(n,1,k) % Mod;
	printf("%I64d\n",res);
	return 0; 
}

おすすめ

転載: blog.csdn.net/aiqiyizz/article/details/85842831