1 条题解
-
0
自动搬运
来自洛谷,原作者为

_2eyks
.搬运于
2025-08-24 23:16:18,当前版本为作者最后更新于2025-08-19 19:37:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
场上半小时才出思路,我太菜了。
注意到 只可能与 交换,所以记录每个数出现的位置 ,然后扫一遍就行。
考虑给每对能互相交换的数连无向边,因为是无向的,所以从前往后扫这个数列。
每扫到一个下标 ,令 ,考虑分别讨论连边 的情况。以与 连边为例:
- 如果 与 有连边,则 这个数可以被移动到 位置,那么 就可以与 交换,遂连边。
- 如果 与 有连边,则如果 ,那么也连边。
与 连边的情况类似。
然后你把连边放并查集上,猜测答案是连通块大小对应 fibonacci 数的乘积,你发现这在赛时能过联考所有大样例。某大神说可用数学归纳法证明。
#include <bits/stdc++.h> using namespace std; #define int long long #define fr first #define sc second #define pii pair<int,int> #define yes cout<<'Y'<<'E'<<'S'<<endl #define no cout<<'N'<<'O'<<endl #define im cout<<-1<<endl #define debug(x) cerr<<#x<<':'<<x<<endl #define fo(i,l,r) for(int i=l;i<=r;i++) #define ro(i,r,l) for(int i=r;i>=l;i--) #define couts(x) cout<<setprecision(x)<<fixed void Ios(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); } const int N=1e6+5,M=998244353; int n,a[N],f[N],r[N]; map<int,int>to; namespace dsu{ int fa[N],siz[N]; int find(int x){ if (fa[x]==x) return x; return fa[x]=find(fa[x]); } void merge(int x,int y){ if (r[x]==x) r[x]=y; // cout<<x<<' '<<y<<'\n'; x=find(x),y=find(y); if (x==y) return; fa[y]=x,siz[x]+=siz[y]; } } using namespace dsu; void solve(){ cin>>n; to.clear(); fo(i,1,n){ cin>>a[i]; fa[i]=i,siz[i]=1,r[i]=i; to[a[i]]=i; if (i>1){ if (abs(a[i-1]-a[i])==1) merge(i-1,i); if (to[a[i]-1]){ int x=to[a[i]-1]; if (r[x]<=x+1){ if (r[x]==i-1) merge(x,i); else if (r[x]==i-2&&abs(a[i-1]-a[i])==1) merge(x,i); } } if (to[a[i]+1]){ int x=to[a[i]+1]; if (r[x]<=x+1){ if (r[x]==i-1) merge(x,i); else if (r[x]==i-2&&abs(a[i-1]-a[i])==1) merge(x,i); } } } } int rs=1; fo(i,1,n) if (find(i)==i) rs=rs*f[siz[i]]%M; cout<<rs<<'\n'; } signed main(){ freopen("disappear.in","r",stdin); freopen("disappear.out","w",stdout); Ios(); f[0]=f[1]=1; fo(i,2,N-1) f[i]=(f[i-1]+f[i-2])%M; int T=1; // cin>>T>>T; while (T--) solve(); return 0; } //30 4 5 3 1 2 13 14 12 11 9 10 7 8 40 22 20 21
- 1
信息
- ID
- 12291
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者