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

题目链接

本人比较的菜,D题是比赛结束后十分钟才把代码打完~  E,F不会~

A. Shuffle Hashing

A题暴力即可

#include
#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
#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

先将1,2,3,4,一直加到小的一部分。。。然后当 a>b 的时候,(a-b)%2==0 的时候,就在1,2,3,4.。。。中选一个偶数分给b即可。。。

#include
#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
#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

C. Berry Jam

设x是红色的个数,y是白色的个数

遍历一遍  前缀记录x-y,用map记录位置即可。。

后缀遍历计算x-y,在map中通过找-(x-y) 得到合法区间即可。。

#include
#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
#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);
        mapmp;
        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
#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
#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 >st;二分当前区间有多少个相交的区间,结合并查集防止有环。

#include
using namespace std;
#define  pi pair
typedef long long ll;
const int N=1e6+10;
pi a[N];
int fa[N];
setst;
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
using namespace std;
const int N=1e6+10;
vectorG[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

 

你可能感兴趣的:(codeforce题解,数据结构---线段树)