Educational Codeforces Round 78 (Rated for Div. 2)(A,B,C,D(另類暴力)E(巧妙dfs))

題目鏈接

本人比較的菜,D題是比賽結束後十分鐘才把代碼打完~  E,F不會~

A. Shuffle Hashing

A題暴力即可

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
char s[N],t[N];
int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%s%s",s+1,t+1);
        int n=strlen(s+1);
        int m=strlen(t+1);
        int f=1;
        int vis[30],vs[30];
        for(int i=0;i<26;++i) vis[i]=0,vs[i]=0;

        for(int i=1;i<=n;++i) vis[s[i]-'a']++;

        for(int i=1;i+n-1<=m&&f;++i){
            for(int i=0;i<26;++i) vs[i]=0;
            for(int j=i;j<=i+n-1;++j){
                vs[t[j]-'a']++;
            }
            bool flag=1;
            for(int j=0;j<26&&flag;++j){
                if(vs[j]!=vis[j]) {
                    flag=0;
                    //printf("j:%d\n",j);
                }
            }
            if(flag) f=0;
        }
        if(!f) puts("YES");
        else puts("NO");
    }
}

B. A and B

假設a<b

先將1,2,3,4,一直加到小的一部分。。。然後當 a>b 的時候,(a-b)%2==0 的時候,就在1,2,3,4.。。。中選一個偶數分給b即可。。。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
ll a,b;
ll dp[N],num[N];
int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%lld%lld",&a,&b);
        if(a==b){
            puts("0");
            continue;
        }
        if(a<b) swap(a,b);
        ll d=a-b;
        ll sum=0;
        ll ans=1;
        while(sum<d||((sum-d)%2!=0)){
            sum+=ans;
            ans++;
        }
        printf("%lld\n",ans-1);
    }
}

C. Berry Jam

設x是紅色的個數,y是白色的個數

遍歷一遍  前綴記錄x-y,用map記錄位置即可。。

後綴遍歷計算x-y,在map中通過找-(x-y) 得到合法區間即可。。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
int dp[N][3],f[N][3],n,a[N],b[N];

int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%d",&n);
        map<int,int>mp;
        n=2*n;
        int x=0,y=0;
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        int ans=n;
        rep(i,1,n/2)
        {
            if(a[i]==1) x++;
            else y++;
            if(x==y) ans=min(ans,n-i);
            mp[x-y]=i;
        }

        x=0,y=0;
        for(int i=n;i>=n/2+1;--i){
            if(a[i]==1) x++;
            else y++;
            if(x==y) ans=min(ans,i-1);
            if(mp[-(x-y)]!=0) ans=min(ans,i-mp[-(x-y)]-1);
        }

        printf("%d\n",ans);
    }
}

D. Segment Tree

做法1:線段樹(已被HACK)

hack數據:

5

1 4

2 5

3 6

7 9

8 10 求聯通塊有問題

樹的特點:邊數=n-1,然後是一個聯通塊。。

連通塊好計算,一層for求區間並即可

邊數怎麼求呢?

從前往後遍歷,遇到左區間,就線段樹上點更新,遇到右區間就查詢區間和,就是邊數。。

我寫了兩顆線段樹(正着一遍 反着一遍)來判斷是否有獨立的點,感覺沒必要,寫多了(有求連通塊就可以了)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;

int n,vis[N],vs[N];
pi a[N],b[N];
ll sum[N*4],s[N*4];
void up(int id,int l,int r,int pos,int val,int ty)
{
    if(l==r) {
        if(ty) sum[id]+=val;
        else s[id]+=val;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,val,ty);
    else up(id<<1|1,mid+1,r,pos,val,ty);
    if(ty) sum[id]=sum[id<<1]+sum[id<<1|1];
    else
    s[id]=s[id<<1]+s[id<<1|1];

}
ll qu(int id,int l,int r,int ql,int qr,int ty)
{
    if(ql<=l&&r<=qr){
        if(ty)
        return sum[id];
        else return s[id];
    }
    ll res=0;
    int mid=l+r>>1;
    if(ql<=mid) res+=qu(id<<1,l,mid,ql,qr,ty);
    if(qr>mid) res+=qu(id<<1|1,mid+1,r,ql,qr,ty);
    return res;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a[i].first,&a[i].second);
        b[i].first=a[i].first;
        b[i].second=a[i].second;
        vis[a[i].first]=i;
        vis[a[i].second]=i;
    }
    if(n==1){
        puts("YES");
        return 0;
    }
    sort(b+1,b+1+n);
    int flag=1;

    int l=b[1].first,r=b[1].second;
    for(int i=1;i<=n&&flag;++i){
        bool tmp=0;

        if(b[i].first<=r) tmp=1;
        l=min(l,b[i].first);
        r=max(r,b[i].second);

        if(!tmp) flag=0;
    }
    if(!flag){
        puts("NO");
        return 0;
    }
    ll ans=0;
    for(int i=2*n;i>=1;--i){
        int id=vis[i];
        if(a[id].second==i){
            up(1,1,2*n,a[id].second,1,1);
        }
        else{
            ll t;
            t=qu(1,1,2*n,a[id].first,a[id].second,1)-1;
            up(1,1,2*n,a[id].second,-1,1);
            if(t>0) ans+=t,vs[id]=1;
        }
    }

    for(int i=1;i<=2*n;++i){
        int id=vis[i];
        if(a[id].first==i){
            up(1,1,2*n,a[id].first,1,0);
        }
        else{
            ll t;
            t=qu(1,1,2*n,a[id].first,a[id].second,0)-1;
            up(1,1,2*n,a[id].first,-1,0);
            if(t>0) vs[id]=1;
        }
    }

    int f=1;
    for(int i=1;i<=n&&f;++i) if(vs[i]==0) f=0;

    if(f&&ans==n-1) puts("YES");
    else puts("NO");
}

做法2:

線段樹求聯通塊有問題,那麼就換種方式,開始想的是如何在線段樹節點上保存所有區間內的區間標號。。

看了別人的代碼,就是用set<pair<int,int> >st;二分當前區間有多少個相交的區間,結合並查集防止有環。

#include<bits/stdc++.h>
using namespace std;
#define  pi pair<int,int>
typedef long long ll;
const int N=1e6+10;
pi a[N];
int fa[N];
set<pi >st;
int n;
int fin(int x)
{
    if(fa[x]!=x) fa[x]=fin(fa[x]);
    return fa[x];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a[i].first,&a[i].second);
        fa[i]=i;
    }
    sort(a+1,a+1+n);
    int f=1;
    ll ans=0;
    for(int i=1;i<=n&&f;++i){
        auto l=st.lower_bound(make_pair(a[i].first,0));
        auto r=st.lower_bound(make_pair(a[i].second,0));
        for(auto it=l;it!=r&&f;++it){
            int f1=fin(i);
            int f2=fin((*it).second);
            if(f1==f2) f=0;
            else{
                fa[f1]=f2;
                ans++;
            }
        }
        st.insert(make_pair(a[i].second,i));
    }
    if(f&&ans==n-1) puts("YES");
    else puts("NO");
}

E. Tests for problem D

這題跟D題相反,現給你一顆樹,能否構造一個D題一樣的區間。。

有相交但不包含的區間就有一條邊

l1  l2   r1   r2  代表着有一條邊 ,l1 l2 r2 l1不算

做法:很妙的做法,看代碼就懂了:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>G[N];
int n,cnt,l[N],r[N];
void dfs(int u,int fa)
{
    for(int v:G[u]){
        if(v==fa) continue;
        l[v]=++cnt;
    }
    r[u]=++cnt;
    for(int i=G[u].size()-1;i>=0;--i){
        if(G[u][i]==fa)continue;
        dfs(G[u][i],u);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    l[1]=++cnt;
    dfs(1,0);
    for(int i=1;i<=n;++i) printf("%d %d\n",l[i],r[i]);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章