Codeforces Round #764 (Div. 3)

Codeforces Round #764 (Div. 3)
TMD,div3也能被暴打....呜呜呜!
写完了D,就卡壳了,真的是遇到困难睡大觉,真的去睡觉了...

E. Masha-forgetful

先来看E题,目标就是用一些字符串的某些区间去表示一个目标串。要求区间的长度至少为2.
我就说cf的构造题有意思吧。考虑倘若一个合法的可能解,那么他表示的这些区间,一定能分解为长度为2,3的小区间。所以我们只对目标串中的长度为2,3的小区间进行匹配,之后可以做一下DP去覆盖整个字符串即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int t,n,m,id2[N],l2[N],id3[N],l3[N],l[N],r[N],id[N];
char s[N],c[N][N]; 
bool f[N];
inline void clear()
{
    for(int i=0;i<=m;++i) 
    {
        id2[i]=0;l2[i]=0;
        id3[i]=0;l3[i]=0;
        f[i]=0;
    }
    f[0]=true;
}
int main()
{
//    freopen("1.in","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%s",c[i]+1);
        scanf("%s",s+1);
        clear();
        for(int i=1;i<m;++i)
        {
            bool flag=false;
            for(int j=1;j<=n;++j)
            {
                for(int k=1;k<m;++k)
                {
                    if(s[i]==c[j][k]&&s[i+1]==c[j][k+1])
                    {
                        id2[i]=j;l2[i]=k;
                        flag=true;break;
                    }
                }
                if(flag) break;
            }
        }
        for(int i=1;i<m-1;++i)
        {
            bool flag=false;
            for(int j=1;j<=n;++j)
            {
                for(int k=1;k<m-1;++k)
                {
                    if(s[i]==c[j][k]&&s[i+1]==c[j][k+1]&&s[i+2]==c[j][k+2])
                    {
                        id3[i]=j;l3[i]=k;
                        flag=true;break;
                    }
                }
                if(flag) break;
            }
        }
        for(int i=0;i<m;++i)
        {
            if(f[i]&&id2[i+1]) f[i+2]=true;
            if(f[i]&&id3[i+1]) f[i+3]=true;
        }
        if(!f[m]) {puts("-1");continue;}
        int tot=0,s=m;
        while(s)
        {
            if(f[s-2])
            {
                id[++tot]=id2[s-1];
                l[tot]=l2[s-1];
                r[tot]=l[tot]+1;
                s-=2;
            }
            else
            {
                id[++tot]=id3[s-2];
                l[tot]=l3[s-2];
                r[tot]=l[tot]+2;
                s-=3;
            }
        }
        printf("%d\n",tot);
        for(int i=tot;i>=1;--i) printf("%d %d %d\n",l[i],r[i],id[i]); 
    }
    return 0;
}

G. MinOr Tree

接下来看最后一题,这个题题意也很简单:求或起来的最小生成树。
记得之前做过在一堆数中找到两个数使得他们或起来最大或最小。和这个题方法一模一样...真的是记忆力....
首先位运算我们都是可以一位一位考虑的,然后从最高位考虑,看最高位能否为0,这个时候检查下,最高位为0的边,我们能否联通接口,接下来一位位的往下做即可。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n,m,f[N],vis[N];
struct bian{int x,y,v;}b[N]; 
inline int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}
inline bool check(int md)
{
    for(int i=1;i<=n;++i) f[i]=i;
    for(int i=1;i<=m;++i)
    {
        if(!vis[i]||((1<<md)&b[i].v)!=0) continue;
        int t1=getf(b[i].x),t2=getf(b[i].y);
        if(t1!=t2) f[t1]=t2;
    }
    int st=getf(1);
    for(int i=1;i<=n;++i) if(getf(i)!=st) return false;
    return true;
}
int main()
{
//    freopen("1.in","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i) 
        {
            scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].v);
            vis[i]=1;   
        }
        int ans=0;
        for(int i=30;i>=0;--i)
        {
            if(check(i))
            {
                for(int j=1;j<=m;++j) if((1<<i)&b[j].v) vis[j]=0;
            }
            else ans+=1<<i;
        }
        printf("%d\n",ans);
    }
    return 0;
}

F. Interacdive Problem

f的交互题也不难,因为他给的数据,n为1000,询问次数最多为10,而2^10=1024.这不明摆着二分吗?但这个10次着实是把二分卡到了极致,不能有一次是多余的。考虑%n的同余系上找答案。每次回答的答案只给x/n的值,那么通过这次与上次的值是否相同,我们可以得到余数是否跨越了一个n。通过这样,每次将余数所在的区间缩小一般。而关于二分,一定注意边界条件控制好。代码简单,就是...啧啧啧

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;scanf("%d",&n);
    int l=1,r=n-1;
    int last=0;
    while(l<r)
    {
        int mid=l+r>>1;
        printf("+ %d\n",n-1-mid);
        fflush(stdout);
        int x;scanf("%d",&x);
        if(x==last) r=n-1,l=r-(mid-l);
        else l=0,r=r-mid-1;
        last=x;
    }   
    printf("! %d\n",last*n+l);
    fflush(stdout);
    return 0; 
} 
原文地址:https://www.cnblogs.com/gcfer/p/15788457.html