牛客 - 牛牛的最大兴趣组(思维+数论)
題目鏈接:點擊查看
題目大意:給出 nnn 個數,要求選出最多的數,使得任意兩個數的乘積不能是三次平方數,三次平方數,諸如23=8,33=272^3=8,3^3=2723=8,33=27
題目分析:這個模型和前兩天 cfcfcf 上遇到的一個樣:CodeForces - 1497E2
這個模型的特點就是,假設要使得任意兩個數的乘積不能是 mmm 次平方數的話,當我們將所有的數字中,出現次數為 mmm 的倍數的質因子都篩掉后,剩下的數一定會兩兩匹配。具體到某個質因子來說,假設其出現次數為 xxx,那么其需要和出現次數為 m?xm-xm?x 的數字匹配,其乘積后該質因子的出現次數才能被 mmm 整除
下面就將本模型擴展到 mmm 次平方數來思考如何求解
又因為經過上述的處理后,除了 111 之外,其他的數都有且僅有唯一一個數字與其匹配。也就是對于每個數來說,只有一個數字與其乘積會不滿足條件,所以這兩個數字肯定不能同時出現。既然如此貪心去想的話,保留出現次數較多的那個數字顯然是最優的
到此本題的思路就已經解決了,現在留下來兩個難點需要我們逐個思考:
針對第一點,最樸素的做法就是 O(n)O(\sqrt{n})O(n?) 的唯一分解定理了,對于出現次數可以被 mmm 整除的質因子直接舍棄即可,可惜時間復雜度不允許
然后考慮也比較常用的,預處理出每個數字的最小質因子,然后 O(logn)O(logn)O(logn) 去篩質因子,這種實現時間復雜度可行,但是我們無法預處理到 2e92e92e9 的數據范圍
其實我們不難發現,并不需要枚舉出所有的質因子然后判斷,我們的目標是為了篩掉所有 mmm 次平方數的數字,換句話說我們可以預處理出 mmm 次平方的數字,然后用這些數字去篩即可,而這樣的 mmm 次平方數,最多有 2e9m\sqrt[m]{2e9}m2e9? 個數字,又因為合數總是可以被分解成質數,所以我們只需要保留質因子即可,這樣有效數字最終約等于 2e9mlogm\frac{\sqrt[m]{2e9}}{logm}logmm2e9??,針對本題而言,當 m=3m=3m=3 的時候,這個數值約等于 200200200
那么還剩下一個問題,如何找到對應的數字呢,實際上最樸素的做法還是 O(n)O(\sqrt{n})O(n?) 去唯一分解這個數,如果對于某個質因子 ppp,其出現次數是 xxx,那么其對應的那個數字, ppp 的出現次數一定是 m?xm-xm?x
到此為止,網上的部分題解,都是 O(nn)O(n\sqrt{n})O(nn?) 實現的,因為本題數據水了,所以給放過去了,其實一組很簡單的 hackhackhack 樣例就是, nnn 個 1e9+71e9+71e9+7,直接就把復雜度卡成至少 1e5?1e4=1e91e5*1e4=1e91e5?1e4=1e9 起步了
所以該如何去查找對應的那個數字呢,假設我們要找 xxx 對應的數字,只需要將 xxx 變成 xm?1x^{m-1}xm?1,然后再將出現次數為 mmm 的質因子篩掉即可,具體原理就是:對于任意兩個相鄰的自然數來說,都是互質的,所以 gcd(m?1,m)=1gcd(m-1,m)=1gcd(m?1,m)=1,對于公式 a+a?(m?1)=a?ma+a*(m-1)=a*ma+a?(m?1)=a?m,兩邊同時對 mmm 取模得到 a+a?(m?1)=0∣ma+a*(m-1)=0|ma+a?(m?1)=0∣m,所以將 xxx 變為 xm?1x^{m-1}xm?1 然后再將出現次數為 mmm 的倍數的質因子篩掉就可以找到對應的數字了
總的時間復雜度就是 O(n2e9m)O(n\sqrt[m]{2e9})O(nm2e9?),對于本題而言就是 O(200?n)O(200*n)O(200?n),實現的時候我套了個 mapmapmap ,理論上說應該是不可以的,但因為本題數據水,所以是可以過的,如果是正解的話我感覺需要打個哈希降一下復雜度,大概就是 unordered_map 了
代碼:
// Problem: 牛牛的最大興趣組 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/7604/C // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; bool vis[N]; vector<int>pri; map<LL,int>mp; void init() {for(int i=2;i<=2000;i++) {if(vis[i]) {continue;}for(int j=i+i;j<=2000;j+=i) {vis[j]=true;}}for(int i=2;1LL*i*i*i<=2e9;i++) {if(!vis[i]) {pri.push_back(i*i*i);}} } LL change(LL x) {for(auto it:pri) {while(x%it==0) {x/=it;}}return x; } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n;read(n);for(int i=1;i<=n;i++) {LL x;read(x);mp[change(x)]++;}int ans=0;for(auto &it:mp) {if(it.first==1) {ans++;continue;}LL rk=change(it.first*it.first);if(!mp.count(rk)) {ans+=it.second;} else {ans+=max(it.second,mp[rk]);it.second=mp[rk]=0;}}cout<<ans<<endl;return 0; }總結
以上是生活随笔為你收集整理的牛客 - 牛牛的最大兴趣组(思维+数论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 兰州大学第一届『飞马杯』程序设计竞赛 -
- 下一篇: 牛客 - 牛牛的滑动窗口(单调栈+思维+