2024牛客多校第三場

liyishui發表於2024-07-24

磨合上升期,爽!

B

隊友做的

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
const int N=105;
int n,d,p,res;
int h[N];
int gcd(int x,int y){
    if (y==0) return x;
    return gcd(y,x%y);
}
signed main()
{
    cin >> n >> d;
    for (int i=1;i<=n;i++)
        cin >> h[i];
    p=h[n];
    for (int i=1;i<n;i++)
        p=gcd(p,h[i]);
    res=d%p;
    if (res>p/2) res=p-res;
    cout << res << endl;
    return 0;
}

L

#include<bits/stdc++.h>
using namespace std;
const int N=9;
char ch[N+5][N+5];
void Kafka()
{
    for(int i=1;i<=N;++i) scanf("%s",ch[i]+1);
    bool flag=1;
    for(int i=1;i<=N;putchar('\n'),++i) for(int j=1;j<=N;++j)
    {
        if(i>1&&i<N&&j>1&&j<N&&ch[i][j]=='8'&&flag) putchar('8'),flag=0;
        else putchar('*');
    }
}
signed main()
{
    Kafka();
    return 0;
}

J

對於這類 "每個點都是1出度,指向的點可以確定" 的題,經典做法是倍增跳

23年的杭電多校也有一道類似的,問走x步在環上走到哪裡,那題想到倍增直接做完

這題比較麻煩的地方在於要先預處理出f[i]表示i到的點才能進行倍增

預處理可以用二分/倍增實現

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int n,a,b;
char s[N+5];

//PART 1:
int sum[N+5];
pair<int,bool> f[N+5];
void Get_Prefix()
{
    sum[1]=s[1]^48;
    for(int i=2;i<=n;++i) sum[i]=sum[i-1]+(s[i]^48);
}
inline int QueryA(int L,int R){return L<=R?sum[R]-sum[L-1]:0;}
inline int QueryB(int L,int R){return L<=R?R-L+1-QueryA(L,R):0;}
int check(int L,int R,int A,int B)
{
    if(A+QueryA(L,R)>=a) return 1;
    else if(B+QueryB(L,R)>=a) return 0;
    return -1;
}
int check(int A,int B)
{
    if(A>=a) return 1;
    else if(B>=a) return 0;
    return -1;
}
int Find_Len(int L,int R,int A,int B)
{
    int l=1,r=R-L+1;
    for(int mid=l+r>>1;l<r;check(L,L+mid-1,A,B)>-1?r=mid:l=mid+1)mid=l+r>>1;
    return l;
}
int Find_Nums(int A,int B)
{
    int l=0,r=(2*a-1)/n+1,tmpA=QueryA(1,n),tmpB=QueryB(1,n);;
    for(int mid=l+r+1>>1;l<r;check(A+mid*tmpA,B+mid*tmpB)>-1?r=mid-1:l=mid) mid=l+r+1>>1;
    return l;
}
void Kafka()
{
    cin>>n>>a>>b;
    cin>>s+1;
    Get_Prefix();
//    for(int i=1;i<=n;++i) printf("sum[%d]=%d\n",i,sum[i]);
    for(int i=1;i<=n;++i)
    {
        if(~check(i,n,0,0))
        {
            int tmp=Find_Len(i,n,0,0);
            f[i]=make_pair(i+tmp,check(i,i+tmp-1,0,0));
            if(f[i].first>n) f[i].first-=n;
        }
        else
        {
            int nums=Find_Nums(QueryA(i,n),QueryB(i,n));
            int A=QueryA(i,n)+nums*QueryA(1,n),B=QueryB(i,n)+nums*QueryB(1,n);
            if(A>=a) f[i]=make_pair(1,1);
            else if(B>=a) f[i]=make_pair(1,0);
            else 
            {
                int tmp=Find_Len(1,n,A,B);
                f[i]=make_pair(1+tmp,check(1,tmp,A,B));
                if(f[i].first>n) f[i].first-=n;    
            }
        }
    } 
//    for(int i=1;i<=n;++i) printf("f[%d]=%d and %d\n",i,f[i].first,f[i].second);
}

//PART 2:
const int LIMIT=18;
pair<int,int> g[LIMIT+5][N+5];
int Gcheck(int A,int B)
{
    if(A>=b) return 1;   
    else if(B>=b) return 0;
    return -1;
}
int Ans(int x)
{
    int A=0,B=0;
    for(int i=LIMIT-1;~i;--i)
    {
        int Len=1<<i,tmpA,tmpB;
        tmpA=g[i][x].second,tmpB=Len-tmpA;
        if(~Gcheck(A+tmpA,B+tmpB)) continue;
        x=g[i][x].first,A+=tmpA,B+=tmpB;
    }
    A+=g[0][x].second;
    if(A>=b) return 1;
    else return 0;
}
void Himeko()
{
    for(int i=1;i<=n;++i) g[0][i]=f[i];
    for(int i=1;i<LIMIT;++i) for(int j=1;j<=n;++j)
    {
        g[i][j].first=g[i-1][g[i-1][j].first].first;
        g[i][j].second=g[i-1][j].second+g[i-1][g[i-1][j].first].second;
    }
//    for(int i=0;i<LIMIT;++i) for(int j=1;j<=n;++j) printf("g[%d][%d]:%d and %d\n",i,j,g[i][j].first,g[i][j].second);
    for(int i=1;i<=n;++i) cout<<(char)(Ans(i)^48);
}
signed main()
{
    Kafka();
    Himeko();
    return 0;
}

A

思路一直假了,在那邊用一種求得出方案的nlog做法寫模擬,掛了兩發後實在找不到返利,開始貪心

貪心的實質就是算供給,運過去需要的最少次數S為 (n-r)/(r-l) ,能提供的總次數為 Σ min( (h[i]-1)/2, S)

Σ min( (h[i]-1)/2, S) >= S*L 即可

證明還是很妙的,數學歸納法

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
const int N=5e5+505;
int n,l,r;
int h[N],d[N];

bool sol(){
    if (n<l) return false;
    for (int i=1;i<=n;i++){
        int x=(h[i]-1)/2;
        d[1]++;
        d[x+1]--;
    }
    for (int i=1;i<=n;i++)
        d[i]+=d[i-1];
    int cnt=0,sum=0,k=r-l;
    for (int i=1;i+r<n+1;i+=k){
        cnt++;
        sum+=d[cnt];
        if (sum<cnt*l) return false;
    }
    return true;
}

signed main()
{
    cin >> n >> l >> r;
    for (int i=1;i<=n;i++)
        h[i]=read();
    
    if (sol()) cout << "Yes" << endl;
        else cout << "No" << endl;
    return 0;
}

J

給定n塊兩端都有數字的骨牌,要求排列它們使得任意相鄰的兩端都不相等,排列時可以指定某個骨牌左右順序

本來想到了奇怪的圖論最佳化建圖去,在那邊網路流流了半天沒網出來

首先注意到如果兩端都不相等,假設有x個,那麼這x個怎麼排都可以,如果撞了反一下就好 ........①

如果兩端都相等,假設有y個,問題轉化為給定長度為y的陣列a[i](其中a[i]表示第i個數出現的次數)

每次都可以挑兩個出來對消,問要怎麼構造使得剩下的最少?

經典結論是:每次挑眾數和隨便一個數去刪,只要眾數<=sum/2,偶數能消完,奇數剩一個。否則眾數>sum/2,一定會有剩餘

實現時我用了小根堆,每次pop兩次堆頭對消

到這裡處理完了兩端都相同的,不妨假設剩下的為(1,1)

還沒用上的骨牌裡如果有(2,1) (3,1)(4,1)這種一端相同的也全部可以接上去

最後還剩兩端不一樣 && 兩端都≠1的,這就和 ① 一樣了

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n;
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
int xid[N<<1],tot[N<<1],x[N],y[N];
int cntx=0,flag=1;
struct node{
    int c,v;
    /*
    
    
    bool operator
    */
    bool operator <(const node &b)const{return v==b.v?c<b.c:v>b.v;}
    bool operator >(const node &b)const{return v==b.v?c>b.c:v<b.v;}
};
priority_queue<node,vector<node>,greater<node>>q;
void solve(){
    n=read();
    for(int i=1;i<=n;i++){
        x[i]=read(),y[i]=read();
        xid[++cntx]=x[i];
        xid[++cntx]=y[i];
    }
    sort(xid+1,xid+1+cntx);
    cntx=unique(xid+1,xid+1+cntx)-(xid+1);
    
    int sum=0;
    vector<pair<int,int>>a;
    for(int i=1;i<=n;i++){
        int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid);
        int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid);
        if(x[i]==y[i]){
            tot[idx]++;
        }
        else a.push_back({idx,idy});
    }
    int most=0,val=-1;
    for(int i=1;i<2*N;i++){
        if(!tot[i]) continue;
        q.push((node){i,tot[i]});
        sum+=tot[i];
        if(tot[i]>most){
            most=tot[i],val=i;
        }
    }
    int flag=0;
    int last=-1;
    vector<pair<int,int>>out;
    if(!most){
        flag=1;
        for(auto v:a){
            if(v.first==last){
                out.push_back({v.second,v.first}); last=v.first;
                continue;
            }
            if(v.second==last){
                out.push_back({v.first,v.second}); last=v.second;
                continue;
            }
            out.push_back({v.first,v.second});
            last=v.second;
        }
    }
    else {
        if(most<=sum/2){ // 1.clear
            int left=0;
            flag=1;
            while(!q.empty()){
                auto u=q.top();
                q.pop();
                if(q.empty()==true) {
                    left=u.c;
                    break;    
                }
                auto v=q.top();
                q.pop();
                out.push_back({u.c,u.c});
                out.push_back({v.c,v.c});
                last=v.c;
                u.v--;v.v--;
                if(u.v) q.push(u);
                if(v.v) q.push(v);     
            }
            if(left) {
                out.push_back({left,left});
                last=left;
            }
            
            
            
            for(auto v:a){
                if(v.first==last){
                    out.push_back({v.second,v.first}); last=v.first;
                    continue;
                }
                if(v.second==last){
                    out.push_back({v.first,v.second}); last=v.second;
                    continue;
                }
                out.push_back({v.first,v.second});
                last=v.second;
            }
        }
        else {
            node tmp;
            while(!q.empty()){
                auto u=q.top();
                q.pop();
                if(q.empty()==true) {
                    tmp=u;
                    break;    
                }
                auto v=q.top();
                q.pop();
                out.push_back({u.c,u.c});
                out.push_back({v.c,v.c});
                last=v.c;
                u.v--;v.v--;
                if(u.v) q.push(u);
                if(v.v) q.push(v);     
            }
            
            out.push_back({tmp.c,tmp.c});
            last=tmp.c;
            tmp.v--;
            int cnt=0;
            for(int i=1;i<=n;i++){
                if(x[i]==y[i]) continue;
                int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid);
                int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid);
                if(idx==tmp.c){
                    out.push_back({idy,idx});
                }
                else if(idy==tmp.c){
                    out.push_back({idx,idy});
                }
                else cnt++;
            }
            
            if(cnt>=tmp.v) {
                flag=1;
                for(int i=1;i<=n;i++){
                    if(x[i]==y[i]) continue;
                    int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid);
                    int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid);
                    if(tmp.v&& idx!=tmp.c&&idy!=tmp.c){
                        out.push_back({idx,idy});
                        out.push_back({tmp.c,tmp.c});
                        last=tmp.c;
                        tmp.v--;
                    }
                    else {
                        if(idx==tmp.c || idy==tmp.c ) continue;
                        
                        if(idx!=last){
                            out.push_back({idx,idy});
                            last=idy;
                        }
                        if(idy!=last){
                            out.push_back({idy,idx});
                            last=idx;
                        }
                    }
                }
            }
        }        
    }
    
    if(!flag){
        cout<<"NO"<<"\n";
    }
    else {
        cout<<"YES"<<"\n";
        for(auto v:out){
            cout<<xid[v.first]<<" "<<xid[v.second]<<"\n";
        }
    }
}
signed main()
{
    solve();
    return 0;
}

相關文章