P2564 [SCOI2009]生日礼物
P2564 [SCOI2009]生日禮物
題意:
n個(gè)彩珠,k個(gè)種類,分布在一個(gè)彩帶上,現(xiàn)在要選取彩帶的一部分,要求該部分包含所有種類的彩珠,且長(zhǎng)度盡可能短,你能計(jì)算這個(gè)最短的長(zhǎng)度嗎?
1≤N≤1000000,1≤K≤60,0≤珠子位置<2{31}
題解:
比賽時(shí)第一反應(yīng)是尺取,但是一看這個(gè)距離放棄了,后來(lái)想可以先離散?或者map距離,因?yàn)榉N種原因都沒(méi)做出,現(xiàn)在賽后補(bǔ)題
實(shí)質(zhì)用的是區(qū)間伸縮
因?yàn)橹樽拥奈恢梅秶艽?#xff0c;但是珠子的數(shù)量有限,所以我們完全可以枚舉珠子的數(shù)量
我們給每種彩珠編號(hào)以及存下每種彩珠的坐標(biāo)
然后根據(jù)坐標(biāo)排序
然后就是區(qū)間伸縮(我一直認(rèn)為是尺取),兩個(gè)指針l和r,分別指向左右兩端的兩種珠子,在一半題中我們都會(huì)讓指針指向距離的左右兩端,但是因?yàn)楸绢}距離過(guò)長(zhǎng),所以我們使其指向左右兩端彩珠(即第i個(gè)彩珠和第j個(gè)彩珠)
左端l更新情況是:如果第l個(gè)彩珠和第l-1個(gè)彩珠在一個(gè)位置,那我們就l++,以l+1個(gè)彩珠為新的起點(diǎn)
相當(dāng)于我們以不同的彩珠作為左端點(diǎn),然后枚舉右端點(diǎn),當(dāng)num == m時(shí),說(shuō)明目前這個(gè)區(qū)間上有了所有的彩珠
(u1s1我也將不大很明白,就是把尺取距離變成尺取每種彩珠)
詳細(xì)看看代碼把
代碼:
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } const int maxn=1000008; struct node{int pos;//位置 int id;//種類 }a[maxn]; int b[maxn];//用來(lái)統(tǒng)計(jì)每種彩珠的出現(xiàn)次數(shù) bool cmp(node a,node b) {return a.pos<b.pos; } int main() {int n,k;cin>>n>>k;int tot=0;for(int i=1;i<=k;i++){int t;cin>>t;for(int j=1;j<=t;j++){cin>>a[++tot].pos;a[tot].id=i;}}sort(a+1,a+1+tot,cmp);int l=1,r=1;int num=0;//記錄當(dāng)前彩帶上有多少種彩珠b[a[l].id]++;//先將第一個(gè)彩珠記錄 num++;int sum=1e9;//最后記錄答案 while(l<=n&&r<=n){if(num==k){sum=min(sum,a[r].pos-a[l].pos);//更新答案 b[a[l].id]--;if(b[a[l].id]==0)num--;//離開(kāi)l點(diǎn)l++;if(l>n)break;while(a[l].pos==a[l-1].pos)//如果移動(dòng)后還是原來(lái)那個(gè)位置 {b[a[l].id]--;if(b[a[l].id]==0)num--;l++;if(l>n)break;}}else {r++;if(r>n)break;b[a[r].id]++;if(b[a[r].id]==1)num++; while(a[r].pos==a[r+1].pos){r++;if(r>n)break;b[a[r].id]++;if(b[a[r].id]==1)num++;}}} cout<<sum; }總結(jié)
以上是生活随笔為你收集整理的P2564 [SCOI2009]生日礼物的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 联通的家庭网关怎么和路由器桥接联通光猫桥
- 下一篇: 动态规划专题复习