con5多校聯盟 (李主席與階乘)

2021-08-04 22:54:22 字數 4420 閱讀 3808

李主席對10000內的階乘能倒背如流,有一天學妹請教李主席乙個問題,需要對這樣乙個式子進行化簡:

a[i]!乘積/b[i]!

化成c

1 !^e1*c2!^e2…

t 使得c1最大情況下e1最大,

再使得c2最大。。。

tip:

思路大概是這樣的:

先質因數分解ai得階乘。。。再這一部分,3!*9!*5!這種,排序:3!*5!*9!,於是1 2 3出現3次,4 5 兩次,6 7 8 9三次,就是可以直接統計出來每個數字自己出現了多少,然後一次質因數分解這個數字(最多10000)就好了

同理對b

a/b可得。。叫做p

顯然如果某個指數出現了負數,就說明沒法湊出答案要的東西,然後在思考,如何使得c1最大,這個時候考慮c1最大是第乙個大於10000得素數-1(記為now)(下乙個素數肯定不會出現,也就不可能能分解出來他的階乘) 依次遞減列舉(now–),每次就相當於把now這個質因數分解,相應的指數減掉就是(now-1)!

現在需要知道能湊出來多少個(now-1)!,可能湊不出來,就是(now-1)!每個指數/p得相應指數,這維護成最小堆就剛剛好,堆頂就是能湊成多少個,每次now減少的時候heap_down一下,如果可以我們堆裡所有的元素都要減這個堆頭,這樣複雜毒比較高,考慮在外面設定累加器sub,堆得值-sub才是真正多少,但是這時候就出現了問題,當我now變成now-1的時候,怎麼能保證值-sub還是對的(比得數減小了)

考慮維護乙個pre_a 代表上一次這個質因數所需質數變化之後還剩多少這個質因數,-外面sub*上次變化後得對這個因數得需要,得出真實值還要+sub和堆裡別的統一

pre_a就減去(減少多少個這個因數)*之前的sub sub是成功的,對於每個成功得,都用了比now-1多得這部分,減掉之後就保證了正確性

heap[_index[j]].h_cnt = (heap[_index[j]].pre_a-sub * tt)/pfac_b[j] + sub

;heap[_index[j]].pre_a = heap[_index[j]].pre_a-cj*sub

; heap[_index[j]].n_cnt = pfac_b[j];

其餘得小chick:

再統計每個數得質因子得時候,(我們的目的是對於任意數字k,快速找到其所有質因子)可以:

首先列舉每個質數,然後統計每個數有多少個質因數,然後給他這麼多得空間放置他的質因數

然後對於每個素數,所有有他作為銀子的數都給個位置,把它放進去:

for(int i = 0 ; i

< cnt ; i++)

}for(int i = 2; i

<= prime_max ; i++)

countprimefac[i] += countprimefac[i-1],cont[i] += cont[i-1];

for(int i = 0 ; i

< cnt ;i++)

for(int j = prime[i] ; j

<= prime_max ; j+= prime[i])

列舉時候「

for(int j = cont[i-1]+1; j <= cont[i];j++)

}

素數篩:

for(int i = 2; i

< maxn ; i ++)

for(int j = 2 * i ; j

< maxn; j += i)

}}

/*

1.首先打素數表,

對於每個a1!*a2!*...an!把a1a2...an排序,裡面每個數字個數都知道啦(on)

然後對於每個1~n做質因數分解,就知道了指數得值(osqrt(n))

以上處理了分子和分母,相減,如果有負數直接return -1,剩下就是原式值每個質因數得指數了

2.對於大於10000得第乙個質數-1,是可能出現的最大數滿足階乘可能夠上面得值,設他是n(sqrt(n)*n)得時間分解n!得質因數

然後n依次變小,看能不能分解出來,能的話堆裡所有數都要-多少個n分解,這個在外面放累加器out

堆是個維護(每個因數多少個/需要多少個)得最小堆,(結點還要和存本來多少個和是哪個質數)

當n--時候,相當於n得質因數分解出來的那些質數得指數剪掉分解出來的,堆裡面得值需要變化,log(pi(n))找到,

-out的值/需要 +out 放回堆裡//down——heap

*/#include

#include

#include

#include

#include

#include

#include

using namespace std;

const int maxn = 10010;

const int maxm = 10100;

const int mm = 1500+10;

const int inf = 1e9;

int prime[mm] ;

int cnt,n,m,a[maxm],b[maxm],cnt,sub,cntans;

int ansa[maxn],ansb[maxn],pfac_a[mm],pfac_b[mm],prime_max;

int c[maxm],e[maxm],_index[maxn],size,to[maxn],notprim[maxn];

int cont[maxn*10],countprimefac[maxn*10],primefac[maxn*10];

struct nodeheap[maxm];

void init()

for(int j = 1; j <= m ; j++)

for(int i = 0 ; i < mm ; i++)

pfac_a[i] = pfac_b[i] = 0;

for(int i = 0 ; i < maxn ; i++)

ansa[i] = ansb[i] = 0;

}void getprim()

for(int j = 2 * i ; j < maxn; j += i)}}

for(int i = 0 ; i < cnt ; i++)

}for(int i = 2; i <= prime_max ; i++)

countprimefac[i] += countprimefac[i-1],cont[i] += cont[i-1];

for(int i = 0 ; i < cnt ;i++)

for(int j = prime[i] ; j <= prime_max ; j+= prime[i])

}void getfactor(int i,int num,int f)

}// cout << "tmp "

<" to"

<333

461015

20void sov()

}for(int k = 1; k < maxn; k++)

}for(int i = 1; i <= m ;i++)

}for(int k = 1; k < maxn; k++)

}int check()

if(pfac_a[k] && pfac_b[k])}}

// for(int k = 0; k < cnt ; k++)

return1;}

void heap_up(int ind)

else

break;

ind /= 2;

}}void heap_down(int ind)

if(heap[ind].h_cnt < heap[ind/2].h_cnt)

else

break;

}}//這個數再a裡,b裡面是要求得c1(迴圈減小ing)

void get_heap()

}}void decrease(int tmp)

}}void findans(int k)

int i = tmp;

for(int jj = cont[i-1]+1; jj <= cont[i];jj++)

j = primefac[jj];

if(cj)

else

heap[_index[j]].h_cnt = inf;

heap_down(_index[j]);}}

k--;

}}int mak_heap()

}if(i == -1)

if(tmp == 1)

}findans(tmp);

return0;}

void print()

}int main()

return0;}

/*5617

610113

55137

75*/

多校聯盟 con1 數學題

現在有兩個陣列 a b 所有a裡的元素 所有b裡面的元素中第k大的是什麼 二分答案,檢驗有沒有k 1個比他大的時候,排序兩個陣列 可使用雙指標,乙個從a陣列最後開始,乙個從b陣列最後乙個開始,如果這個比當前的答案大,那麼b陣列前面的,分母減小,比值肯定都大於答案,直接 m個,如果比答案小,減小b的值...

弱校聯盟con 7 失戀得小T(字尾陣列)

小 t 最近失戀了,開始懷疑人生和愛情,他想知道在這世界中去偽存真後還剩多少。小 t 在網上拿到了代表大千世界的長字串,刪掉了所有換行空格和標點符號,只剩下了小寫字母。現在字串中有好多重複的子串,相同子串裡只有乙個是 real 的。為了讓小 t 走出失戀,你一定要告訴他這個世界上 real 的東西有...

2013 多校聯合5

1005 若沒有邊權,則對點權從大到小排序即可。考慮邊,將邊權拆成兩半加到它所關聯的兩個點的點權中即可。因為當兩個人分別選擇不同的點時,這一權值將互相抵消。智商是硬傷啊 include include include includeusing namespace std double w 10000...