日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【poj3709】 K-Anonymous Sequence

發(fā)布時(shí)間:2024/4/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【poj3709】 K-Anonymous Sequence 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://poj.org/problem?id=3709?(題目鏈接)

題意

  給出一個(gè)n個(gè)數(shù)的序列,要求將其中一些數(shù)改為另一個(gè)比它小的數(shù),改動(dòng)的花費(fèi)為兩數(shù)的絕對(duì)值,完成改動(dòng)后使得整個(gè)序列中出現(xiàn)過的數(shù)出現(xiàn)的次數(shù)大于等于K。求最小花費(fèi)。

Solution

  將原序列從大到小排序以后,我們可以發(fā)現(xiàn),每次把連續(xù)的一段改成相同的數(shù)總是比離散的修改更優(yōu)。于是我們寫出dp方程:${f[i]=Min(f[j]+s[i]-s[j]-a[i]*(i-j))}$。${f[i]}$表示將前${i}$個(gè)數(shù)修改,并且第${i}$個(gè)數(shù)保持不變的最小費(fèi)用;${s[i]}$表示前綴和;${a[i]}$表示第${i}$個(gè)數(shù)的值。

  考慮優(yōu)化。斜率式:${-a[i]*j+f[i]=(f[j]-s[j])+s[i]-a[i]*i}$。

  然而我們發(fā)現(xiàn)斜率${-a[i]}$并不是單調(diào)的,所以就不能夠直接取單調(diào)隊(duì)列隊(duì)首的元素了,那怎么辦呢?只好在隊(duì)列中二分了,二分的過程很好理解,詳情見代碼。

  以上作廢,我在說什么鬼話→_→,${-a[i]}$顯然是單調(diào)的。。

  再附張圖,這次的單調(diào)隊(duì)列里面的點(diǎn)構(gòu)成的圖形有點(diǎn)鬼。。竟然是個(gè)類似于反比例函數(shù)的東西→_→

?

細(xì)節(jié)

  記得開long long。。。

代碼

// poj3709 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf 1ll<<60 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std;const int maxn=500010; LL a[maxn],f[maxn],s[maxn]; int n,K,q[maxn];bool cmp(int a,int b) {return a>b; } double slope(int x,int y) {return (double)((f[y]-s[y])-(f[x]-s[x]))/(double)(y-x); } int main() {int T;scanf("%d",&T);while (T--) {scanf("%d%d",&n,&K);for (int i=1;i<=n;i++) scanf("%lld",&a[i]);sort(a+1,a+1+n,cmp);for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i];for (int i=1;i<=n;i++) f[i]=inf;int l=1,r=1;q[1]=0;for (int i=K;i<=n;i++) {while (l<r && slope(q[l],q[l+1])<-a[i]) l++;f[i]=f[q[l]]+s[i]-s[q[l]]-a[i]*(i-q[l]);while (l<r && slope(q[r-1],q[r])>slope(q[r],i-K+1)) r--;q[++r]=i-K+1;}printf("%lld\n",f[n]);}return 0; }

代碼(強(qiáng)行二分)

// poj3709 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf 1e18 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std;const int maxn=500010; LL f[maxn],s[maxn],a[maxn]; int q[maxn],n,K;double slope(int x,int y) {return (double)((f[y]-s[y])-(f[x]-s[x]))/(double)(y-x); } int find(int l,int r,LL x) {int res=l;while (l<=r) {int mid=(l+r)>>1;if (mid<r && x>slope(q[mid],q[mid+1])) l=mid+1,res=mid;else if (mid>l && x<slope(q[mid-1],q[mid])) r=mid-1,res=mid;else return mid;}return res; } bool cmp(LL a,LL b) {return a>b; } int main() {int T;scanf("%d",&T);while (T--) {scanf("%d%d",&n,&K);for (int i=1;i<=n;i++) scanf("%lld",&a[i]);sort(a+1,a+1+n,cmp);for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i];for (int i=1;i<=n;i++) f[i]=inf;int l=1,r=1;q[1]=0;for (int i=K;i<=n;i++) {int x=find(l,r,-a[i]);f[i]=f[q[x]]+s[i]-s[q[x]]-a[i]*(i-q[x]);while (l<r && slope(q[r-1],q[r])>slope(q[r],i-K+1)) r--;q[++r]=i-K+1;}printf("%lld\n",f[n]);}return 0; }

  

轉(zhuǎn)載于:https://www.cnblogs.com/MashiroSky/p/6011890.html

總結(jié)

以上是生活随笔為你收集整理的【poj3709】 K-Anonymous Sequence的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。