bzoj 1119 [POI2009] SLO & bzoj 1697 牛排序 —— 置換+貪心
阿新 • • 發佈:2018-12-03
題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1119
https://www.lydsy.com/JudgeOnline/problem.php?id=1697
原序列到目標序列的置換,可以找出一些迴圈節;
發現如果按順序把一個迴圈節換下來,如果長度為 l,則第一個數被算了 l-1 次,其它數都是 1 次;
為了代價最小,還可以利用迴圈節外面的數,做法就是先把它換進來,然後讓它算 l-1 次,再換出去;
貪心地取個 min 即可;原來還想過一開始把數字作為位置,位置作為數字,則代價就算在位置上了,但是這樣找出了迴圈節,似乎不一定是能按順序換的...
程式碼如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const xn=1e4+5,inf=1e5+5; int n,w[xn],t[xn],b[xn],mn,mnn,sta[xn],tot,ans,sum; bool vis[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'bzoj 16979'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } void dfs(int x) { sta[++tot]=x; vis[x]=1; mn=min(mn,w[x]); sum+=w[x]; if(!vis[b[x]])dfs(b[x]); } int main() { n=rd(); mnn=inf; for(int i=1;i<=n;i++)w[i]=t[i]=rd(),mnn=min(mnn,w[i]); sort(t+1,t+n+1); for(int i=1,x;i<=n;i++) { x=lower_bound(t+1,t+n+1,w[i])-t; b[x]=i; } for(int i=1;i<=n;i++) { if(vis[i])continue; tot=0; mn=inf; sum=0; dfs(i); if(tot==1)continue; ans+=min(sum+mn*(tot-2),sum+mn+mnn*(tot+1)); } printf("%d\n",ans); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=1e6+5; int n,w[xn],t[xn],a[xn],b[xn],mn,sta[xn],tot,mnn; ll ans,sum; bool vis[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } void dfs(int x) { sta[++tot]=x; vis[x]=1; mn=min(mn,w[x]); sum+=w[x]; if(!vis[b[x]])dfs(b[x]); } int main() { n=rd(); mnn=6505; for(int i=1;i<=n;i++)t[i]=rd(),mnn=min(mnn,t[i]); for(int i=1,x;i<=n;i++)x=rd(),a[x]=i,w[i]=t[x];// for(int i=1,x;i<=n;i++)x=rd(),b[i]=a[x]; for(int i=1;i<=n;i++) { if(vis[i])continue; tot=0; mn=6505; sum=0; dfs(i); ans+=min(sum+(ll)mn*(tot-2),sum+mn+(ll)mnn*(tot+1)); } printf("%lld\n",ans); return 0; }bzoj 1119