2 条题解
-
0
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n,m,a[300010],dp[300010],la[300010],ans[300010]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m; int l=0,cnt=0; for(int i=1;i<=m;i++){ cin>>a[i]; l=max(l,la[a[i]]); cnt+=!la[a[i]]; la[a[i]]=i; if(i-l==cnt&&dp[l]!=-1)dp[i]=dp[l]+1; else dp[i]=-1; } int p=-1; for(int i=m;i>=l;i--){ if(dp[i]!=-1&&p==-1)p=i; else if(dp[i]!=-1&&dp[i]<dp[p])p=i; } if(p==-1){ cout<<-1; return 0; } for(int i=1;i<=n;i++)ans[i]=dp[p]+1; for(int i=1;i<=p;i++)ans[a[i]]--; for(int i=1;i<=n;i++){ cout<<ans[i]<<" "; } return 0; } -
0
题目大意
给定序列 ,构造一个长度为 的序列 ,使得第 次操作前 ,操作后给 加一,求字典序最小解。
数据范围:。
思路分析
观察 的操作过程,把 相同的若干操作划分成一段,那么每次操作会让所有最小值 。
对于同一段的操作,不可能有 相等,并且上一段的 会被下一段的 包含。
不难发现满足这两个条件的划分方式一定是合法的,并且我们只要最小化划分轮数即可求出字典序最小解。
设 表示 的最小划分轮数,容易发现左端点 有一个下界,并且要求 的数被 包含,显然 越小越好,因此可以直接贪心。
注意最后一轮可以不划分满,即在倒数第二轮所有可能的终止点 中取 最小的一个,重复时取 最大的一个。
时间复杂度 。
代码呈现
#include<bits/stdc++.h> using namespace std; const int MAXN=3e5+5; int n,m,a[MAXN],pre[MAXN],dp[MAXN],ans[MAXN]; signed main() { scanf("%d%d",&m,&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); int lst=0,cnt=0; for(int i=1;i<=n;++i) { lst=max(lst,pre[a[i]]),cnt+=!pre[a[i]],pre[a[i]]=i; if(i-lst==cnt&&~dp[lst]) dp[i]=dp[lst]+1; else dp[i]=-1; } int o=-1; for(int i=n;i>=lst;--i) if(~dp[i]&&(o==-1||dp[i]<dp[o])) o=i; if(o==-1) return puts("-1"),0; for(int i=1;i<=m;++i) ans[i]=dp[o]+1; for(int i=1;i<=o;++i) --ans[a[i]]; for(int i=1;i<=m;++i) printf("%d ",ans[i]); puts(""); return 0; }
- 1
信息
- ID
- 2519
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 2
- 上传者