1 条题解
-
0
彩蛋
由于是日常模拟赛,就没有特意去卡各种假贪心,能过多少随缘。
暴力
一个指数暴力,可以拿分。
#include <bits/stdc++.h> #define ll long long #define maxn 505 #define mod 998244353 using namespace std; int n; int vis[1<<20],g[21][21],a[21]; int best=0; void dfs(int sta,int now) { best=max(best,now); if (vis[sta]) return; vis[sta]=1; int pre=-1; for (int i=0;i<n;i++) if ((sta>>i)&1) { if (pre==-1) pre=i; else { if (g[pre][i]>1) { dfs(sta^(1<<pre),now+1); dfs(sta^(1<<i),now+1); } pre=i; } } } int main() { cin>>n; for (int i=0;i<n;i++) cin>>a[i]; for (int i=0;i<n;i++) for (int j=i;j<n;j++) g[i][j]=g[j][i]=__gcd(a[i],a[j]); dfs((1<<n)-1,0); cout<<best<<endl; }
正解
我们考虑最终序列的形态,一定是
xxxoooxooxoxoxoooxoooxooox
类的。其中,
x
表示这个位置被删掉了,o
表示这个位置留下来了。考虑到这个,我们就可以先预处理一个数组,表示能否把区间的元素全都删掉。
此处隐含了一个信息是:我们假设此时没有被删掉。
那么$ok_{l,r}=\max(ok_{l,k-1}\&ok_{k+1,r}\&[gcd(a_k,a_{l-1})>1 \ \ or\ \ gcd(a_k,a_{r+1})>1])$
接下来就可以直接
dp
了:表示我留下了,前个元素中最多能留多少个元素。
。
通过预处理数组可以做到的复杂度。
#include <bits/stdc++.h> #define ll long long #define maxn 505 #define mod 998244353 using namespace std; int n; int a[maxn],g[maxn][maxn],ok[maxn][maxn]; int dp[maxn]; int main() { cin>>n; for (int i=1;i<=n;i++) cin>>a[i]; a[0]=a[n+1]=1; for (int i=0;i<=n+1;i++) for (int j=i;j<=n+1;j++) g[i][j]=g[j][i]=__gcd(a[i],a[j]); for (int l=1;l<=n+1;l++) ok[l][l-1]=1; for (int len=1;len<=n;len++) for (int l=1;l+len-1<=n;l++) { int r=l+len-1; for (int k=l;k<=r;k++) if (g[l-1][k]!=1 || g[r+1][k]!=1) if (ok[l][k-1] && ok[k+1][r]) ok[l][r]=1; // if (ok[l][r]) cout<<l<<" "<<r<<endl; } memset(dp,-1,sizeof(dp)); dp[0]=0; for (int i=0;i<=n;i++) if (dp[i]!=-1) { for (int j=i+1;j<=n+1;j++) if (ok[i+1][j-1]) dp[j]=max(dp[j],dp[i]+(j-i-1)); } // for (int i=0;i<=n+1;i++) cout<<dp[i]<<" "; cout<<dp[n+1]<<endl; }
- 1
信息
- ID
- 1428
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 90
- 已通过
- 9
- 上传者