zoukankan      html  css  js  c++  java
  • VK CUP2017 ROUND 1

    来自FallDream的博客。未经允许,请勿转载,谢谢。

    ----------------------------------------------------

    和ditoly组队打vkcup,原来以为是正常div2难度,结果发现.....不说了 AB都被叉了一遍,又掉分 .......

    -------------------------

    A.给定n个人和m组朋友关系,判断这个图是否满足性质:如果x和y是朋友,y和z是朋友,那么x和z是朋友 n,m<=150000

    题解:很容易发现满足关系的图是团,所以我们对每个联通块判一下就可以了。

    n的范围很奇怪,我没注意,结果被hack了,发现150000*149999会爆int....

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int cnt=0,n,m;
    struct edge{
        int to,next;
    }e[300005];
    int head[300005];
    ll num,sum;
    bool mark[300005];
    
    inline void ins(int u,int v)
    {
        e[++cnt].next=head[u];head[u]=cnt;
        e[cnt].to=v;
    }
    
    void dfs(int x)
    {
        mark[x]=1;num++;
        for(int i=head[x];i;i=e[i].next,sum++)if(!mark[e[i].to])
            dfs(e[i].to);
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {int  a=read();int  b=read();ins(a,b);ins(b,a);}
        for(int i=1;i<=n;i++)if(!mark[i])
        {num=sum=0;dfs(i);
            if(num>2&&sum!=(num-1)*num)return 0*puts("NO");
            //   if(num==2&&sum!=2)return 0*puts("NO");
        }
        puts("YES");
        return 0;
    }

    B.给定n,k,表示有n个名字,然后给定n-k+1个条件,每个条件是YES/NO,表示从它开始的连续k个名字有没有相同的(YES表示没有),你要构造出满足题意的名字,保证有解。n<=50

    题解:我们先把全部都赋成不同的名字,然后从后往前,如果第i个是NO,那么把它变成和i+k-1一样。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #define ll long long
    using namespace std;
    inline int read()
    {
        int  x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int k,cnt=0,n;
    string name[55],s;
    char st[555];
    int res[55];
    
    string getnewname()
    {
        cnt++;s="A";
        for(int i=cnt;i>0;i-=26)s=s+(char)((i-1)%26+'a');
        return s;
    }
    
    int pd(){scanf("%s",st+1);return st[1]=='Y'?1:0;}
    
    int main()
    {
        n=read();k=read();
        for(int i=1;i+k-1<=n;i++) res[i]=pd();
        for(int i=1;i<=n;i++)name[i]=getnewname();
        for(int i=n-k+1;i;i--)if(res[i]) name[i]=getnewname();
        else name[i]=name[i+k-1];
        for(int i=1;i<=n;i++)cout<<name[i]<<" ";
        return 0;
    } 

    C.有一棵树,每条边的权值是1,然后给定k,表示你一步可以走的距离为k。令Fst表示从s到t要走多少步,求Fij,1<=i<j<=n   n<=200000 k<=5

    题解:乱dp,一个表示走多少步,另一个表示没走满一步的个数。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    char B[1<<26],*S=B,C;int X;
    inline int read()
    {
        while((C=*S++)<'0'||C>'9');
        for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
        return X;
    }
    #define MN 200000
    struct edge{int nx,t;}e[MN*2+5];
    int k,h[MN+5],en,f[MN+5][5];
    long long ans,ff[MN+5];
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void dfs(int x,int fa)
    {
        int i,j,l;
        f[x][0]=1;
        for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
        {
            dfs(e[i].t,x);
            for(j=0;j<k;++j)
            {
                ans+=1LL*f[e[i].t][j]*ff[x]+1LL*f[x][j]*ff[e[i].t];
                for(l=0;l<k;++l)ans+=1LL*f[e[i].t][j]*f[x][l]*((j+l)/k+1);
            }
            for(j=1;j<k;++j)f[x][j]+=f[e[i].t][j-1];
            f[x][0]+=f[e[i].t][k-1];ff[x]+=ff[e[i].t]+f[e[i].t][k-1];
        }
    }
    int main()
    {
        fread(B,1,1<<26,stdin);
        int n=read(),i;k=read();
        for(i=1;i<n;++i)ins(read(),read());
        dfs(1,0);
        cout<<ans;
    }

    D.给定一个长度为n的字符串,每次你可以交换一对连续的字符,求最少的交换次数,使得字符串中没有连续的两个是"VK" n<=75

    题解:我们把不是VK的字符看作一种,然后用f[i][j][k][0/1]表示前i个V,j个K,k个不是VK的字符,最后一位是/不是V的最小交换数。

    我们枚举最后一位放什么,那么它需要额外的交换次数是前i个V,j个K,k个其他字符中在它之后的个数(因为那些要从后面移到前面),然后就可以转移啦。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #define ll long long
    using namespace std;
    inline int read()
    {
        int  x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    vector<int> v,k,o;
    int n;
    char st[100];
    ll f[77][77][77][2];
    
    int main()
    {
        n=read();memset(f,127,sizeof(f));
        scanf("%s",st+1);
        for(int i=1;i<=n;i++)
            if(st[i]=='V') v.push_back(i);
            else if(st[i]=='K')k.push_back(i);
            else o.push_back(i);
        f[0][0][0][0]=0;
        for(int i=0;i<=v.size();i++)
            for(int j=0;j<=k.size();j++)
                for(int l=0;l<=o.size();l++)
                    for(int c=0;c<=2;c++)
                    {
                        if((!i)&&(!c))continue;
                        if((!j)&&c==1)continue;
                        if((!l)&&c==2)continue;
                        int pos,num=0;
                        if(!c) pos=v[i-1];
                        else if(c==1) pos=k[j-1];
                        else pos=o[l-1];//cout<<pos<<endl;
                        for(int m=i;m<v.size()&&v[m]<pos;m++)num++;//cout<<num<<endl;
                        for(int m=j;m<k.size()&&k[m]<pos;m++)num++;//cout<<num<<endl;
                        for(int m=l;m<o.size()&&o[m]<pos;m++)num++;
                    //    cout<<num<<endl;
                        if(c==0)for(int m=0;m<=1;m++) f[i][j][l][1]=min(f[i][j][l][1],f[i-1][j][l][m]+num);
                        if(c==1)for(int m=0;m<=0;m++) f[i][j][l][0]=min(f[i][j][l][0],f[i][j-1][l][m]+num);
                        if(c==2)for(int m=0;m<=1;m++) f[i][j][l][0]=min(f[i][j][l][0],f[i][j][l-1][m]+num);
                    //    cout<<i<<" "<<j<<" "<<l<<" "<<f[i][j][l][0]<<" "<<f[i][j][l][1]<<endl;
                    }
        int a=v.size(),b=k.size(),c=o.size();
        cout<<min(f[a][b][c][0],f[a][b][c][1]);
        return 0;
    } 

    E.给定一个2*n的矩阵,你要选出最多的和为0且不相交的矩阵,求出最多的数量。n<=300000

    题解:记忆化搜索,每次选择比较靠后的往前跳,貌似是卡不掉的。

    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define ll long long
    char B[1<<26],*S=B,C;ll X,F;
    inline ll read()
    {
        for(F=1;(C=*S++)<'0'||C>'9';)if(C=='-')F=-1;
        for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
        return X*F;
    }
    #define MN 300000
    #define d(x,y) make_pair(x,y)
    ll s[MN+5][3];
    int t[MN+5][3],f[MN+5];
    map<ll,int> mp;
    map<pair<int,int>,int> u,ff;
    int cal(int x,int y)
    {
        if(u[d(x,y)])return ff[d(x,y)];
        return u[d(x,y)]=1,ff[d(x,y)]=max(f[min(x,y)],t[x][0]>t[y][1]?cal(t[x][0],y)+1:cal(x,t[y][1])+1);
    }
    int main()
    {
        fread(B,1,1<<26,stdin);
        int n=read()+1,i,j,k,l;
        for(i=2;i<=n;++i)s[i][0]=s[i-1][0]+read();
        for(i=2;i<=n;++i)s[i][1]=s[i-1][1]+read(),s[i][2]=s[i][0]+s[i][1];
        for(l=0;l<3;++l)for(mp.clear(),i=1;i<=n;++i)t[i][l]=max(t[i-1][l],mp[s[i][l]]),mp[s[i][l]]=i;
        f[0]=t[0][0]=t[0][1]=-1;u[d(0,0)]=1;ff[d(0,0)]=-2;
        for(i=2;i<=n;++i)f[i]=max(f[t[i][2]]+1,cal(i,i)),ff[d(i,i)]=f[i];
        printf("%d",f[n]);
    }
  • 相关阅读:
    IOS 网络编程 + 后台保持连接
    关于 UIWindow
    IOS 企业级应用无线部署 详解
    Appium+python自动化(二十四)- 白素贞千年等一回许仙
    Appium+python自动化(二十三)- 真假美猴王Monkeyrunner与Monkey傻傻的分不清楚(超详解)
    Appium+python自动化(二十二)- 三个臭皮匠助你成就一番霸业-控件坐标获取(超详解)
    Appium+python自动化(二十)- 猴哥失散多年的混血弟弟还是妹妹- Monkey(猴子)日志(超详解)
    java接口自动化(一)
    Appium+python自动化(十九)- 猴哥失散多年的混血弟弟还是妹妹- Monkey(猴子)参数(超详解)
    Appium+python自动化(十八)- 你难道是猴哥失散多年的混血弟弟还是妹妹???- Monkey事件(超详解)
  • 原文地址:https://www.cnblogs.com/FallDream/p/vkcup2017round1.html
Copyright © 2011-2022 走看看