CodeForces - 1497E2 Square-free division (hard version)(dp+数论)
題目鏈接:點擊查看
題目大意:給出一個長度為 nnn 的數列,現在最多可以修改 kkk 個數字為任意數值,現在問最少可以將數列劃分成多少個連續的數列,使得每一個單獨的段中,任意兩個數的乘積都不能是完全平方數,完全平方數是指諸如 1,4,9,16{1,4,9,16}1,4,9,16 等
題目分析:先簡單說一下 E1E1E1,E1E1E1 就是 k=0k=0k=0 的情況,正因為少了修改,所以直接貪心即可,依據就是,當遍歷到 xxx 時,若 xxx 可以和前面一段的數字中的任意一個組成完全平方數,則讓 xxx 新開一段,否則就將 xxx 加入前一段一定是最優的
現在問題轉換為了,如何快速判斷前面的一段中是否存在著能和 xxx 組成完全平方數的數字呢?直接去思考完全平方數的因子可就走遠了,考慮完全平方數在進行質因子分解后的特征,顯然所有的質因子都是偶數個的
那么我們可以將 xxx 中所有偶數個數的質因子都刪掉,因為不做貢獻?,F在只剩下了奇數個數的質因子了,而對于奇數個數的質因子,假設有 cntcntcnt 個 ppp,且 cntcntcnt 為奇數,則只有一個 ppp 實際上是有貢獻的,因為 cntcntcnt 個 ppp 可以分解為一個 ppp 和 cnt?1cnt-1cnt?1 個 ppp,在這里 cnt?1cnt-1cnt?1 顯然為偶數,所以不做貢獻
到此為止不難看出,如果兩個數字在將偶數個數的質因子都篩掉之后相等,那么這兩個數的乘積就是一個完全平方數,所以 E1E1E1 的解法就呼之欲出了,只需要開個桶貪心去維護一下就可以了
繼續討論 E2E2E2,因為 kkk 比較小,且是一個待修改的貪心問題,不難想到是 dpdpdp,先設計一下狀態,這個題目本質上還是一種區間劃分問題,那么就設計 dpi,jdp_{i,j}dpi,j? 為到了第 iii 個位置,做了 jjj 次修改后,可以劃分的最小段數,答案顯然就是 dpn,kdp_{n,k}dpn,k? 了
區間劃分問題最基礎的轉移是枚舉最后一段的起點然后進行轉移,時間復雜度至少是 O(n2)O(n^2)O(n2) 級別的
接下來就是我覺得比較難思考的兩個點了,首先第一個點就是需要觀察到,對于本題而言,考慮將 dpi,jdp_{i,j}dpi,j? 的第二維固定后,dpdpdp 的值與第一維的值,是正相關的。簡單來說就是隨著 iii 的單調遞增,dpdpdp 的值是一個非嚴格上升序列
所以對于 dpi,jdp_{i,j}dpi,j? 的轉移,我們只需要找到,盡可能靠前的合法位置進行轉移即可,那么此時我們就需要預處理出一個 “合法” 數組 li,jl_{i,j}li,j? ,代表到了第 iii 個位置,最多可以修改 jjj 次時,可以到達最遠的左端點的位置
單獨考慮預處理的 lll 數組,不難看出就是個簡單的尺取,這樣一來 dpdpdp 方程的轉移復雜度就下降到了 O(nk2)O(nk^2)O(nk2) 了
簡單說一下轉移方程:
dp(i,j)=min(dp(i,j),dp(l(i,t),j?t)+1)dp_{(i,j)}=min(dp_{(i,j)},dp_{(l_{(i,t)},j-t)}+1)dp(i,j)?=min(dp(i,j)?,dp(l(i,t)?,j?t)?+1)
代碼:
// Problem: E2. Square-free division (hard version) // Contest: Codeforces - Codeforces Round #708 (Div. 2) // URL: https://codeforces.com/contest/1497/problem/E2 // Memory Limit: 256 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=2e5+100; const int M=1e7+100; int a[N],cnt,pri[M],mmin[M],num[M],l[N][25],dp[N][25]; bool vis[M]; void P() {for(int i=1;i<M;i++) {mmin[i]=i;}for(int i=2;i<M;i++) {if(!vis[i]) {pri[cnt++]=i;}for(int j=0;j<cnt&&pri[j]*i<M;j++) {mmin[i*pri[j]]=min(mmin[i*pri[j]],i);mmin[i*pri[j]]=min(mmin[i*pri[j]],pri[j]);vis[i*pri[j]]=true;if(i%pri[j]==0) {break;}}} } int only(int x) {int ans=1;while(x!=1) {int tmp=mmin[x];int cnt=0;while(x%tmp==0) {x/=tmp;cnt++;}if(cnt&1) {ans*=tmp;}}return ans; } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);P();int w;cin>>w;while(w--) {int n,k;read(n),read(k);for(int i=1;i<=n;i++) {int x;read(x);a[i]=only(x);for(int j=0;j<=k;j++) {dp[i][j]=inf;}}for(int t=0;t<=k;t++) {int p=1,cnt=0;for(int i=1;i<=n;i++) {num[a[i]]++;if(num[a[i]]>1) {cnt++;}while(cnt>t) {if(num[a[p]]>1) {cnt--;}num[a[p]]--;p++;}l[i][t]=p;}for(int i=p;i<=n;i++) {num[a[i]]--;}}for(int t=0;t<=k;t++) {dp[0][t]=0;}for(int i=1;i<=n;i++) {for(int j=0;j<=k;j++) {for(int t=0;t<=j;t++) {dp[i][j]=min(dp[i][j],dp[l[i][t]-1][j-t]+1);}}}cout<<dp[n][k]<<endl;}return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 1497E2 Square-free division (hard version)(dp+数论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1501C G
- 下一篇: CodeForces - 1494D D