<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Live2D Demo

      Codeforces Round 1020 (Div. 3) CF 2106 A~G2 題解

      人生第一次打過jiangly

      點我看題

      A. Dr. TC

      原串中每一個\(1\)最終的出現次數是\(n-1\),而每個\(0\)最終的出現次數是\(1\)。因此直接統計即可。

      時間復雜度\(O(n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n;
      string s;
      
      int main()
      {
        //fileio();
      
        cin>>t;
        while(t--)
        {
          cin>>n>>s;
          int ans=0;
          rep(i,n) if(s[i]=='1') ans+=n-1;else ++ans;
          cout<<ans<<endl;
        }
      
        return 0;
      }
      

      B. St. Chroma

      為了讓\(x\)盡早作為MEX出現,我們先把小于\(x\)的元素一股腦塞在序列最前面。塞完這些元素之后MEX就是\(x\)了,為了保持,我們接下來優先放\(>x\)的元素,把\(x\)放最后即可。注意特判\(x=n\)的情況。

      時間復雜度\(O(n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n,x;
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n>>x;
          if(n==x)
          {
            rep(i,n) cout<<i<<' ';
            cout<<endl;
            continue;
          }
          rep(i,x) cout<<i<<' ';
          for(int i=x+1;i<n;++i) cout<<i<<' ';
          cout<<x<<endl;
        }
      
        return 0;
      }
      

      C. Cherry Bomb

      首先如果\(b\)中有\(\neq -1\)的元素,那\(ab\)中對應的兩個數之和\(x\)的值就已經確定了,對\([1,n]\)中每個位置檢查是否合法即可。如果\(b\)中只有-1,易發現\(x\)的取值范圍是\([max\{a_i\},k-min\{a_i\}]\),直接計算即可。

      時間復雜度\(O(n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n,k,a[200010],b[200010];
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n>>k;
          rep(i,n) cin>>a[i];
          rep(i,n) cin>>b[i];
          int sum=-1,ok=1;
          rep(i,n) if(b[i]>-1)
          {
            if(sum==-1) sum=a[i]+b[i];
            else if(sum!=a[i]+b[i]) ok=0;
          }
          if(ok==0)
          {
            cout<<0<<endl;
            continue;
          }
          if(sum>-1)
          {
            rep(i,n) if(b[i]==-1&&sum-a[i]>k||sum-a[i]<0) ok=0;
            cout<<ok<<endl;
          }
          else
          {
            int mxa=-1,mna=1e9;
            rep(i,n)
            {
              mxa=max(mxa,a[i]);
              mna=min(mna,a[i]);
            }
            cout<<mna+k-mxa+1<<endl;
          }
        }
      
        return 0;
      }
      

      D. Flower Boy

      下面解析中數組下標從1開始。

      如果序列\(a\)已經固定,我們想要檢查是否能摘到足夠的花,可以采用從開頭開始貪心匹配\(a,b\)序列的方法。即如果\(a_i\geq b_j\),其中\(j-1\)是目前摘的花的數量,那就摘下這朵花并向前走一步;否則,直接向前走一步。方便起見,我們將一對序列\((a_0,b_0)\)使用這種貪心方法摘到的花的數量稱為匹配數

      首先對原序列\((a,b)\)做一次這種匹配,如果匹配數為\(m\),則答案為0。否則,令\(pref_i(i\in[0,n])\)表示\(a\)的前\(i\)個元素與\(b\)的匹配數,\(suf_i(i\in[0,n])\)表示 \(a\)的后\(i\)個元素組成的反向后的序列 與 \(b\)反向后的序列 的匹配數。若插入一個beauty\(=k\)的花能解決問題的話,注意到必存在\(i\)滿足\(pref_i+suf_{n-i}=m-1\),我們此時需要把新的花插入在第\(i\)盆花之后,且它的beauty\(\leq b_{pref_i+1}\)。若這樣的\(i\)不存在,則無解。

      時間復雜度\(O(n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n,m,a[200010],b[200010],pref[200010],suf[200010];
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n>>m;
          rep(i,n) cin>>a[i];
          rep(i,m) cin>>b[i];
          
          pref[0]=(a[0]>=b[0] ? 1:0);
          repn(i,n-1)
          {
            if(pref[i-1]==m) pref[i]=m;
            else if(a[i]>=b[pref[i-1]]) pref[i]=pref[i-1]+1;
            else pref[i]=pref[i-1];
          }
      
          suf[n-1]=(a[n-1]>=b[m-1] ? 1:0);
          for(int i=n-2;i>=0;--i)
          {
            if(suf[i+1]==m) suf[i]=m;
            else if(a[i]>=b[m-suf[i+1]-1]) suf[i]=suf[i+1]+1;
            else suf[i]=suf[i+1];
          }
      
          if(pref[n-1]==m)
          {
            cout<<0<<endl;
            continue;
          }
          int ans=INT_MAX;
          if(pref[n-1]==m-1) ans=b[m-1];
          if(suf[0]==m-1) ans=min(ans,b[0]);
          rep(i,n-1) if(pref[i]+suf[i+1]==m-1) ans=min(ans,b[pref[i]]);
          if(ans==INT_MAX) cout<<-1<<endl;
          else cout<<ans<<endl;
        }
      
        return 0;
      }
      

      E. Wolf

      下面解析中數組下標從1開始。

      \(pos_i\)表示值\(i\)在原序列中的位置。對于一次詢問,若\(pos_x\notin[l,r]\),則顯然無解。否則,我們模擬一下在\([l,r]\)上二分的過程,發現其中存在\(O(log_2n)\)個"關鍵位置",即每次二分中的\(m\),這些位置上的值是決定二分是否成功的關鍵。具體來說,對于其中一些位置我們要求其上的值\(>x\),方便起見我們稱之為B位;對于另一些位置我們要求其上的值\(<x\),稱之為S位

      \([1,n]\)\(>x\)的數的數量小于B位的數量,則無論我們如何操作,都不可能達成目標,此時直接判無解。對于S位也是類似。

      對于位置上的數原本就\(>x\)的B位以及位置上的數原本就\(<x\)的S位(稱它們為好位),我們不去動他們是最好的,比較省操作。對于位置上的數\(<x\)的B位以及位置上的數\(>x\)的S位(稱它們為壞位),令其數量依次為\(b,s\)。稱除了好位、壞位和\(pos_x\)的位置為普通位。注意到,我們需要從普通位中叫一些"外援",把這些外援劃到我們選擇出來并shuffle的\(d\)個元素中。觀察發現至少需要叫\(|b-s|\)個外援才能滿足所有B/S位的"要求",并且一定能選出來(選不出來的情況已經在前面被判無解了)。因此答案為\(2\cdot max(b,s)\)

      時間復雜度\(O(n+qlog_2n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n,q,p[200010],pos[200010];
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n>>q;
          repn(i,n) cin>>p[i],pos[p[i]]=i;
          while(q--)
          {
            int l,r,x;
            cin>>l>>r>>x;
            int targ=pos[x],big=n-x,sml=x-1,nbig=0,nsml=0,nsbig=0,nssml=0;
            if(targ<l||targ>r)
            {
              cout<<-1<<' ';
              continue;
            }
            while(l<r)
            {
              int mid=(l+r)/2;
              if(mid==targ) break;
              if(mid<targ)
              {
                ++nsml;
                if(p[mid]>x) ++nsbig;
                l=mid+1;
              }
              else
              {
                ++nbig;
                if(p[mid]<x) ++nssml;
                r=mid-1;
              }
            }
            if(nbig>big||nsml>sml)
            {
              cout<<-1<<' ';
              continue;
            }
            cout<<max(nsbig,nssml)*2<<' ';
          }
          cout<<endl;
        }
      
        return 0;
      }
      

      F. Goblin

      想象一條向右移動的"掃描線",每次刷新出這個矩陣的一列。注意到每一列中要么只有一個0,要么只有一個1。令掃描線上一個位置的答案表示在掃描線及其左側,包括這個位置的最大的全0連通塊的大小(若這個位置的值為1,則答案為0)。同時,對于掃描線上連續的一堆值為0的位置,它們的答案相同。因此任意時刻,可以把掃描線分成三個區間,其中中間區間的長度為1,滿足每個區間中各位置的答案相同。令這三個區間的答案為\(dp_{i,0/1/2}\)(隨便吧,怎么表示都行)。然后在掃描線相鄰的兩個位置之間就可以用非常無腦的方式進行\(dp\)轉移,這里不再贅述。最終答案對所有\(dp\)值取最大值即可。

      時間復雜度\(O(n)\)

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <LL,LL>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      LL t,n;
      string s;
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n>>s;
          LL l,m,r,ans;
          if(s[0]=='1') m=1,l=r=0,ans=1;
          else l=m=0,r=n-1,ans=n-1;
          repn(i,n-1)
          {
            LL u=i,d=n-i-1;
            if(s[i-1]=='1'&&s[i]=='1') l=r=0,m=1;
            else if(s[i-1]=='1'&&s[i]=='0') l=m+u,m=0,r=d;
            else if(s[i-1]=='0'&&s[i]=='1') l=0,m=r+1,r=0;
            else l+=u,m=0,r+=d;
            ans=max(ans,max(l,m));
            if(i<n-1) ans=max(ans,r);
          }
          cout<<ans<<endl;
        }
      
        return 0;
      }
      

      G2. Baudelaire (hard version)

      n+200次操作?還是在上?這一眼就是個重心分治相關。

      注意到如果我們已經知道了根的位置,我們只需要對每個結點做一次\(k=1\)的1類型詢問,就可以算出每個點的權值。因此考慮怎么使用200次左右的操作找到根的位置。

      我們挑出樹上的任意一條邊來觀察一下。令其直接連接的點為\(a,b\)。將這條邊切斷,樹就分為了 與\(a\)連接的點 和 與\(b\)連接的點 兩個集合。方便起見,稱其為 \(a\)子樹中的點 和 \(b\)子樹中的點。如何判斷樹根在哪個子樹中呢?很簡單,我們先對\(a\)子樹中所有點做一次1詢問,接下來用2詢問改變\(b\)的權值,然后再對\(a\)子樹中所有點做一次1詢問,如果兩次1詢問結果的差值絕對值是 \(a\)子樹中結點個數\(\times 2\),則根在\(b\)子樹中,否則在\(a\)子樹中。這是因為只有在詢問1中涉及的每個結點到根的路徑都經過權值被改變的結點時,詢問結果差值絕對值才會\(=\)詢問結點個數\(\times2\)

      那么能不能每次切斷一條邊直到根可能位于的結點只剩一個呢?不能,因為不存在一個叫邊分治的東西,隨便來一個菊花圖你復雜度就爆炸了。

      考慮重心分治,每輪遞歸嘗試判斷根位于重心的哪個子樹內,或者是不是就是重心本身。分以下幾種情況:

      • 連通塊只剩一個點。那根就是重心本身。
      • 重心(在當前連通塊內)只有一個子樹。那說明連通塊內只有2個點,對重心本身做一次1詢問,若結果為1或-1則重心是根,否則另一個點是根。
      • 重心有不止一個子樹。可能出現以下兩種情況:
        • 重心不是根。考慮在一堆子樹中進行二分,每次用類似上面"判斷根在\(a\)的子樹還是\(b\)的子樹中"的方法來判斷根在 左邊的一堆子樹中 還是 右邊的一堆子樹中(即"先對左邊一堆子樹中所有點做一次1詢問,接下來用2詢問改變重心的權值,然后再對左邊一堆子樹中所有點做一次1詢問"),此時我們可以知道根是否在左邊一堆子樹中,因此可以縮小二分范圍。一輪遞歸使用的詢問數量大約為\(3\cdot log_2(重心的子樹數量)\)
        • 重心是根。在上面那種情況的第一次二分之前,我們先用相同的方法判斷一下,根有沒有一種可能,我是說可能,不在左邊的一堆子樹中,也不在右邊的一堆子樹中。這時候說明重心就是根。

      這樣就優雅地找到了根。接下來用\(n\)次詢問問出每個結點的權值就行了。

      總操作數大約\(n+O(log_2^2n)\),反正肯定是在限制內的。

      其實如果再出惡心一點的話,可以強制要求你"利用"上面找根過程中的詢問,來代替掉這\(n\)個詢問中的一部分。我瞎說的。

      點擊查看代碼
      #include <bits/stdc++.h>
      
      #define rep(i,n) for(int i=0;i<n;++i)
      #define repn(i,n) for(int i=1;i<=n;++i)
      #define LL long long
      #define pii pair <int,int>
      #define fi first
      #define se second
      #define pb push_back
      #define mpr make_pair
      
      void fileio()
      {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
      }
      void termin()
      {
        std::cout<<"\n\nEXECUTION TERMINATED";
        exit(0);
      }
      
      using namespace std;
      
      int t,n,sz[1010],pref[1010],ans[1010],root;
      vector <int> g[1010],subtroots,tmp;
      vector <vector <int> > subts;
      bool vis[1010];
      
      int qry(vector <int> nds)
      {
        cout<<"? 1 "<<nds.size()<<' ';
        rep(i,nds.size()) cout<<nds[i]<<' ';
        cout<<endl;
        cout.flush();
        int ret;cin>>ret;return ret;
      }
      void qry2(int pos)
      {
        cout<<"? 2 "<<pos<<endl;
        cout.flush();
      }
      
      void getSz(int pos,int par)
      {
        sz[pos]=1;
        rep(i,g[pos].size()) if(!vis[g[pos][i]]&&g[pos][i]!=par)
        {
          getSz(g[pos][i],pos);
          sz[pos]+=sz[g[pos][i]];
        }
      }
      pii getMn(int pos,int par,int tot)//{max subtree size, node}
      {
        int mx=1e9,cursz=tot-sz[pos];
        pii ret={mx,114514};
        rep(i,g[pos].size()) if(!vis[g[pos][i]]&&g[pos][i]!=par)
        {
          ret=min(ret,getMn(g[pos][i],pos,tot));
          cursz=max(cursz,sz[g[pos][i]]);
        }
        ret=min(ret,{cursz,pos});
        return ret;
      }
      void getNodes(int pos,int par)
      {
        tmp.pb(pos);
        rep(i,g[pos].size()) if(!vis[g[pos][i]]&&g[pos][i]!=par) getNodes(g[pos][i],pos);
      }
      
      bool isInOther(int lb,int ub,int par)
      {
        int tot=pref[ub+1]-pref[lb];
        vector <int> nds;
        for(int i=lb;i<=ub;++i) rep(j,subts[i].size()) nds.pb(subts[i][j]);
        int res=qry(nds);
        qry2(par);
        int res2=qry(nds);
        return abs(res-res2)==tot*2;
      }
      
      int findRoot(int pos)
      {
        getSz(pos,-1);pos=getMn(pos,-1,sz[pos]).se;
        subts.clear();subtroots.clear();
        rep(i,g[pos].size()) if(!vis[g[pos][i]])
        {
          tmp.clear();
          getNodes(g[pos][i],pos);
          subts.pb(tmp);
          subtroots.pb(g[pos][i]);
        }
        rep(i,subts.size()) pref[i+1]=pref[i]+subts[i].size();
        if(subts.size()==0) return pos;
        if(subts.size()==1)
        {
          int res=qry({pos});
          if(res==1||res==-1) return pos;
          else return subts[0][0];
        } 
        int lb=0,ub=subts.size()-1,mid;
        while(lb<ub)
        {
          mid=(lb+ub)/2;
          bool res=isInOther(0,mid,pos);
          if(lb==0&&ub==subts.size()-1)
          {
            bool res2=isInOther(mid+1,ub,pos);
            if(res&&res2) return pos;
          }
          if(res) lb=mid+1;
          else ub=mid;
        }
        vis[pos]=true;
        return findRoot(subtroots[lb]);
      }
      
      void getAns(int pos,int par,int parval)
      {
        int res=qry({pos});
        ans[pos]=res-parval;
        rep(i,g[pos].size()) if(g[pos][i]!=par) getAns(g[pos][i],pos,res);
      }
      
      int main()
      {
        //fileio();
      
        ios::sync_with_stdio(0);
      
        cin>>t;
        while(t--)
        {
          cin>>n;
          rep(i,n+5) g[i].clear(),vis[i]=false;
          int x,y;
          rep(i,n-1)
          {
            cin>>x>>y;
            g[x].pb(y);
            g[y].pb(x);
          }
          root=findRoot(1);
          getAns(root,0,0);
          cout<<"! ";
          repn(i,n) cout<<ans[i]<<' ';
          cout<<endl;
          cout.flush();
        }
      
        return 0;
      }
      
      posted @ 2025-04-25 01:48  LegendStane  閱讀(596)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 一区二区三区四区自拍视频| 人妻少妇精品无码专区二区 | 亚洲中文字幕无码中字| 国产AV国片精品有毛| 色丁香一区二区黑人巨大| 天堂mv在线mv免费mv香蕉| 国产精品久久久国产盗摄| 久热久热久热久热久热久热 | 熟妇人妻任你躁在线视频| AV免费播放一区二区三区| 国产精品久久久一区二区三区| 国产亚洲精品成人aa片新蒲金| 二区中文字幕在线观看| 日韩区一区二区三区视频| 国产av剧情md精品麻豆| 亚洲乱码一二三四区| 欧美一区二区三区啪啪| 国产免费网站看v片元遮挡| 少妇高潮水多太爽了动态图| 蜜桃精品成人影片| 91久久偷偷做嫩草影院免费看| 六月丁香婷婷色狠狠久久| 国产精品国产三级国快看| 吉川爱美一区二区三区视频| 国产精品成| 一本色道久久综合熟妇人妻| 国产成人亚洲综合| 日韩精品区一区二区三vr| 亚洲国产一区二区av| 色婷婷综合久久久中文字幕| 亚洲 另类 小说 国产精品无码| 国产精品福利自产拍在线观看 | 少妇熟女天堂网av| 日韩乱码人妻无码中文字幕视频| 阿荣旗| 亚洲国产午夜理论片不卡| 国产色爱av资源综合区| 国产无人区码一区二区| 亚洲一区二区中文av| 日韩精品中文字幕无码一区 | 睢宁县|