1. 程式人生 > >牛客小白月賽9 J

牛客小白月賽9 J

/**
J	div.2 A
連結:https://ac.nowcoder.com/acm/contest/275/J

題意:f(n,k) n拆分為k個有序正整數乘積的方案數;
ans = segment( (f(i,k)+i))%mod) i-->[1,n];

分析:f(n,k)=C(num_p1+k-1,k-1)*C(num_p2+k-1,k-1)*.....C(num_pcnt+k-1,k-1)......
num_pi:n不同質因子的數量;
f(n,k):可考慮經典球盒問題,將長度為k的盒子初始化,均賦值為1,將質因子做為球丟進即可;

ans:顯然當前這題是需要趨近於O(n)的方法來實現的,不妨想到尤拉篩選素數;
在篩選過程,每個數可用num[i],記錄i在當前情況下,未用的最小質因子的數量,由此進行遞推即可;
每次i%prime[j]==0,也就是當前的i已經被最小的已經用過的質因子使用過了;
但是可能還存在,對於當前過程,只增加1,遞推可得當前ans;
對於新的質因子表示:用過的質因子的個數已經全部被取完了,*k即可;

如果採用普通的素數篩選方法,貌似會炸空間 且時間複雜度不會得到保證;

*/

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=1e7+7;
const int mod=1e9+7;
int prime[maxn],ans[maxn],num[maxn],cnt=0;

const int inv_num=1e2+7;
int inv[inv_num+3];

int main (){
	ll k;int n;cin>>n>>k;k%=mod;
	inv[1]=1,ans[1]=1;
	for(int i=2;i<=100;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;//質因子數量最多為64:
	for(int i=2;i<=n;i++){
		if(!prime[i]){
			prime[++cnt]=i;
			ans[i]=k,num[i]=1;//素數:
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
			prime[i*prime[j]]=1;
			if(i%prime[j]==0){
				ans[i*prime[j]]=1ll*ans[i]*(num[i]+k)%mod*inv[num[i]+1]%mod;//C(num[i]+k-1,k-1)-->C(num[i]+k-1+1,k-1);
				num[i*prime[j]]=num[i]+1;//引進舊因子;
				break;
			}
			ans[i*prime[j]]=1ll*ans[i]*k%mod;
			num[i*prime[j]]=1;//新查詢的因子
		}
	}
	int ret=0;
	for(int i=1;i<=n;i++) ret^=(ans[i]+i)%mod;
	printf("%d\n",ret);
	return 0;
}