CF1119 Global Round 2

CF1119A Ilya and a Colorful Walk

  • 這題二分是假的.. \(1,2,1,2,1\) 有間隔爲 \(3\) 的,但沒有間隔爲 \(2\) 的.開始被 \(hack\) 了一次.後來改過來了.
  • 個人作法:掃一遍,記錄每一個顏色第一次出現的位置,並存入一個 \(set\) 中,若當前顏色未出現,就更新位置,存入 \(set\) ,不然將那個位置刪除.而後查詢一次 \(set\) 中最小元素.最後再把那個位置插入回去.
  • 官方題解:最遠距離兩個端點中必定包含 \(1\)\(n\) 中至少一個.若 \(c_i\not =c_j,1<i<j<n\) ,那麼若是 \(c_1,c_n\) 不一樣,那麼端點能夠直接選 \(1,n\) ,不然若 \(c_1=c_n\) ,那麼 \(c_1\not = c_j,c_i\not =c_n\) 至少有一個成立,端點也會拓展到邊界上.
  • 找與 \(1​\) 顏色不一樣的點與 \(1​\) 的最遠距離,與 \(n​\) 顏色不一樣的點與 \(n​\) 的最遠距離取 \(\max​\) 便可.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
int n;
const int MAXN=3e5+10;
int c[MAXN];
int check(int x)
{
    for(int i=1;i+x<=n;++i)
        if(c[i]!=c[i+x])
            return 1;
    return 0;
}
int pos[MAXN];
set<int> s;
int main()
{
    n=read();
    s.insert(n+1);
    int ans=0;
    for(int i=1;i<=n;++i)
        {
            int x=read();
            int y=pos[x];
            if(y)
                s.erase(y);
            int p=*s.begin();
            ans=max(ans,i-p);
            if(!pos[x])
                pos[x]=i;
            if(pos[x])
                s.insert(pos[x]);
        }
    cout<<ans<<endl;
    return 0;
}

CF1119B Alyona and a Narrow Fridge

  • 這題二分是真的,能放下前 \(k\) 個顯然就能放下前 \(k-1\) 個嘛.因而二分答案,判斷放前 \(k\) 個是否可行.這裏貪心放,最大的和次大的放在一塊兒,後面同理,排序後兩個兩個放下來便可.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define mp make_pair
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
int n,h;
const int MAXN=1e3+10;
int a[MAXN];
int b[MAXN],tp=0;
bool check(int k)
{
    for(int i=1;i<=k;++i)
        b[i]=a[i];
    sort(b+1,b+1+k);
    int f=0,rs=h;
    for(int i=k;i>=1;--i)
    {
        if(!f)
        {
            rs-=b[i];
            if(rs<0)
                return false;
        }
        f^=1;
    }
    return true;
}
int main()
{
    n=read(),h=read();
    int s=0;
    for(int i=1;i<=n;++i)
        a[i]=read();
    int L=1,R=n;
    int ans=0;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(check(mid))
            ans=mid,L=mid+1;
        else
            R=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}

CF1119C Ramesses and Corner Inversion

  • 注意到這個翻轉操做只改變四個角落的值,不會改變每一行每一列的 \(1\) 個數的奇偶性.
  • 那麼如有一行/列 \(A,B\) 奇偶性不一樣,顯然不合法.
  • 不然?對於每一個不一樣的位置 \((x,y)\) ,咱們都選擇它做爲右下角, \((1,1)\) 做爲左上角進行操做.這樣全部不一樣的地方都被修改到同樣了,而 \(A,B\) 每一行/列奇偶性都相同,多修改的部分 \((1,1),(1,y),(1,x)\) 剛好抵消, \(A\) 就變成了 \(B\) ,因此必定合法.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=512;
int a[MAXN][MAXN],b[MAXN][MAXN];
int main()
{
    int n=read(),m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            a[i][j]=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            b[i][j]=read();
    for(int i=1;i<=n;++i)
    {
        int s1=0,s2=0;
        for(int j=1;j<=m;++j)
            s1+=a[i][j],s2+=b[i][j];
        s1&=1,s2&=1;
        if(s1!=s2)
            return puts("No"),0;
    }
    for(int j=1;j<=m;++j)
    {
        int s1=0,s2=0;
        for(int i=1;i<=n;++i)
            s1+=a[i][j],s2+=b[i][j];
        s1&=1,s2&=1;
        if(s1!=s2)
            return puts("No"),0;
    }
    puts("Yes");
    return 0;
}

CF1119D Frets On Fire

  • 題面太鬼畜了...建議直接看 \(Formally\) 那一段.
  • 首先容易發現, \(s\) 數組的順序對答案是不影響的.因此咱們能夠先將 \(s\) 從小到大排序.
  • 每次詢問 \((l,r)\) ,對於每一個 \(s_i\) ,它所貢獻的數就是 \([s_i+l,s_i+r]\) 這一段,那麼就等價於給了 \(n\) 條長度同樣的線段,問覆蓋的長度.
  • 能夠考慮用整個區間 \([s_1+l,s_n+r]\) 的長度減去中間沒有覆蓋到的部分.容易發現這樣的部分只可能出如今兩條相鄰線段之間,能夠直接用 \(\max(s_{i+1}+l-s_i-r-1,0)\) 來計算.那麼此次詢問的答案就是
    \[ ans=s_n+r-s_1-l+1-\sum_{i=1}^{n-1} \max(s_{i+1}+l-s_i-r-1,0)\\ =s_n+r-s_1-l+1-\sum_{i=1}^{n-1} \max(s_{i+1}-s_i-(r-l+1),0) \]c++

  • \(b_i=s_{i+1}-s_i\) ,將 \(b_i\) 排序後記錄一下前綴和,詢問時二分找出 \(b_i\geq r-l+1\) 的第一個位置,只算後面的部分便可.時間複雜度 \(O(nlogn+qlogn)\) .數組

#include<bits/stdc++.h>
#define inf (1e18)+10
using namespace std;
typedef long long ll;
inline ll read()
{
    ll out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=1e6+10;
ll n,a[MAXN];
ll b[MAXN];
ll sum[MAXN];
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        a[i]=read();
    sort(a+1,a+1+n);
    for(int i=1;i<n;++i)
        b[i]=a[i+1]-a[i];
    sort(b+1,b+n);
    for(int i=1;i<n;++i)
        sum[i]=sum[i-1]+b[i];
    int Q=read();
    while(Q--)
    {
        ll l=read(),r=read();
        ll s=r-l+1;
        ll ans=a[n]+r-a[1]-l+1;
        if(s>b[n-1])
        {
            cout<<ans<<' ';
            continue;
        }
        int p=lower_bound(b+1,b+n,s)-b; 
        ans-=sum[n-1]-sum[p-1];
        ans+=1LL*(n-p)*s;
        cout<<ans<<' ';
    }
    return 0;
}

CF1119E Pavel and Triangles

  • 能夠發現, \(2^i+2^j>2^k,i\leq j \leq k\) 有解,只多是 \(i\leq j,k=j\) .
  • 那麼直接貪心選,每次讀入了 \(x\)\(2^i\) ,就先嚐試用兩個 \(i\) 與以前剩下的任意一個 \(j\) 配對,再嘗試 \((i,i,i)\) 三個配對,再將剩餘的留着,後面再用.
  • 爲何要先嚐試 \((i,i,i)\) 三個配對呢?由於若是不進行這一步,它在以後的步驟中每想造成一個三角形就還須要 \(2\) 個木棍構成 \((i,j,j)\) 的形式,顯然劣於 \((i,i,i)\) 直接配對.
  • 官方證實.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=3e5+10;
int a[MAXN];
ll ans=0,rest=0;
int main()
{
    int n=read();
    for(int i=1;i<=n;++i)
        {
            int x=read();
            ll p=min(1LL*x/2,rest);
            ans+=p;
            rest-=p;
            x-=p*2;
            ans+=x/3;
            x%=3;
            rest+=x;
        }
    cout<<ans<<endl;
    return 0;
}
相關文章
相關標籤/搜索