zoukankan      html  css  js  c++  java
  • 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; 
    } 
    
  • 相关阅读:
    学生管理系统代写
    学生竞赛评价系统
    《划时代51单片机C语言全新教程》前言
    《划时代51单片机C语言全新教程》第三章 开发环境 概览
    校验和
    NBOOT分析-S3C244xInit.s(1)
    《划时代51单片机C语言全新教程》第一章 8051简介 概览
    《划时代51单片机C语言全新教程》第二章 STC89C52RC 处理器 概览
    ARM9中断调试(1)
    NBOOT分析-NBOOT.c(2)
  • 原文地址:https://www.cnblogs.com/gcfer/p/15788457.html
Copyright © 2011-2022 走看看