李主席對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...