UR #13 Yist
生活随笔
收集整理的這篇文章主要介紹了
UR #13 Yist
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第一次打UR,打了一個半小時就棄療了QAQ
這是我唯一一道考試的時候做出來的題目,其他兩道連暴力都懶得寫了
很容易發現對于每個要刪除的點
我們找到左邊第一個比他小的不用刪除的點,右邊第一個比他小的不用刪除的點
中間這段區間就是對于這個點被刪除時的極大區間
對于所有的區間我們取min就可以了
對于找到某個點左邊第一個比他小的不用刪除的點
我是這樣考慮的:將數從大到小的進行添加,并用并查集維護不用刪除的點
那么之后這個點存在的極大區間顯然是這段區間里的1的個數+1
這個算法是O(na)的
#include<cstdio> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> using namespace std;const int maxn=1000010; int n,T,ans; int a[maxn],pos[maxn]; char b[maxn]; int L[maxn],R[maxn]; int sum[maxn]; int ufsL(int x){return L[x]==x?x:L[x]=ufsL(L[x]);} int ufsR(int x){return R[x]==x?x:R[x]=ufsR(R[x]);} void read(int &num){num=0;char ch=getchar();while(ch<'!')ch=getchar();while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void Solve(){for(int i=1;i<=n;++i){if(b[i]=='1')sum[i]=sum[i-1]+1;else sum[i]=sum[i-1];}ans=n;L[0]=0;for(int i=1;i<=n;++i){if(b[i]=='1')L[i]=i;else L[i]=ufsL(i-1);}R[n+1]=n+1;for(int i=n;i>=1;--i){if(b[i]=='1')R[i]=i;else R[i]=ufsR(i+1);}for(int i=n;i>=1;--i){int p=pos[i];if(b[p]=='1'){L[p]=ufsL(p-1);R[p]=ufsR(p+1);}else{int A=ufsL(p);int B=ufsR(p);ans=min(ans,sum[B-1]-sum[A]+1);}}return; } int main(){read(n);for(int i=1;i<=n;++i)read(a[i]),pos[a[i]]=i;scanf("%d",&T);while(T--){scanf("%s",b+1);Solve();printf("%d\n",ans);}return 0; }
題解給出了一種O(n)的做法,還是回顧剛才的思路
我們注意到我們的并查集只有刪除操作
也就是說如果一個點擴展的時候訪問到之前已經擴展過的點
這個點的區間長度一定比之前擴展的那個點的區間長度要長
由于我們取的是min,所以我們就不用擴展了
這樣我們就可以保證每個元素只訪問一次,每次暴力擴展即可
時間復雜度顯然是O(n)的
轉載于:https://www.cnblogs.com/joyouth/p/5381103.html
總結
以上是生活随笔為你收集整理的UR #13 Yist的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BOM字符(#8203;)转textNo
- 下一篇: 内存管理-ARC