zoukankan      html  css  js  c++  java
  • Simple Final Test 题解

    往届学长的一场比赛.   

    总结:三道水题 haha!   

    Task 1 省选 jloi.cpp/in/out 

    给你一个字符串,你每次只能删除一个回文串,问你最少需要几步将字符串删完,或输出无解.  

    题解:显然,答案最多为 2,而如果这个串本身就不是回文串答案就是 1,所以难点就是判断无解的情况.    

    手画几组发现无解有两种情况:s[1...len/2] 与 s[n-len/2+1....n] 回文(这里是向下取整),和 abababababa 这种两个字母交替的形式.  

    判一下就好了. 

    总结:很快想到了答案只有 3 种情况,但是开始的时候没有讨论好无解的情况. 正式考试中的话肯定会打一个表肉眼找找规律吧,属于简单题.  

    #include <bits/stdc++.h>    
    #define N 100009   
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)    
    using namespace std; 
    int n; 
    char str[N];  
    int check1() 
    {
        int len=n/2,flag=0;  
        for(int i=1;i<=len;++i) if(str[i]!=str[n-i+1]) flag=1;  
        return flag;   
    }
    int check3() 
    {
        int len=n/2,f1=1,f2=1;   
        // 中间相等  
        for(int i=2;i<=len;++i) if(str[i]!=str[i-1]) f1=0;         
        if(str[len]!=str[n-len+1]) f1=0;   
        for(int i=n-len+2;i<=n;++i) if(str[i]!=str[i-1]) f1=0;      
        // printf("%d
    ",flag);  
        // 奇偶对称   
        if(n&1)  
        {   
            for(int i=3;i<=n;i+=2)   
                if(str[i]!=str[i-2]) f2=0;   
            for(int i=4;i<n;i+=2)     
                if(str[i]!=str[i-2]) f2=0; 
        }
        else f2=0;   
        return f1||f2;    
    }
    void solve() 
    {   
        scanf("%d%s",&n,str+1);  
        if(check1())  printf("1
    ");  
        else if(check3()) printf("-1
    "); 
        else printf("2
    ");  
    }
    int main() 
    { 
        // setIO("jloi");        
        int T; 
        scanf("%d",&T); 
        for(int i=1;i<=T;++i) 
        {
            solve();      
        } 
        // while(T--) solve();  
        return 0;  
    }
    

      

    Task 2 祝 good.cpp/in/out

    给定一张有向图,每次可以选择若干个没有先后继关系的点进行删除.  

    求:最少要几步才能将所有点删没.   

    题解:刚开始看到这道题的时候没什么思路,然后就想着能否从入度为 0 的点开始删.  

    显然,如果选择这张图初始状态下所有入度为 0 的点进行删除的话其他所有点都是不可以选的.  

    然后思考了一下感觉这样做貌似十分有道理,就写了一个程序,然后就过了.   

    总结:正统的做法应该马上想到答案不小于于最长链长度,然后发现每次删除入度为 0 的点可以达到这个下界.     

    难度不大,但是有些代码细节需要注意.  

    #include <cstdio> 
    #include <ctime>  
    #include <cstring> 
    #include <algorithm>    
    #include <map> 
    #include <stack> 
    #include <queue>  
    #include <vector>  
    #define N 1000009 
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)  
    using namespace std;    
    int n,m; 
    stack<int>S;  
    queue<int>q;  
    map<int,int>vis[N];  
    vector<int>G[N];  
    int low[N],dfn[N],idx[N],size[N],tim,scc;   
    int hd[N],to[N],nex[N],deg[N],f[N],edges;     
    void add(int u,int v) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
    }     
    void tarjan(int x) 
    { 
        S.push(x),dfn[x]=low[x]=++tim;  
        for(int i=hd[x];i;i=nex[i]) 
        {
            int y=to[i];   
            if(!dfn[y]) 
            {
                tarjan(y);  
                low[x]=min(low[x],low[y]);  
            }
            else if(!idx[y]) low[x]=min(low[x],dfn[y]);   
        }     
        if(dfn[x]==low[x]) 
        {
            ++scc;  
            for(;;) 
            {
                int u=S.top(); S.pop();  
                idx[u]=scc;   
                ++size[scc];  
                if(u==x) break;  
            }
        }
    }
    char *p1,*p2,buf[100000];  
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)    
    int rd() 
    {
        int x=0; char c;  
        do { c=nc(); } while(c<48);                   
        while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();   
        return x;   
    }
    int main() 
    { 
        // setIO("good");             
        // int T=clock();    
        int x,y,z; 
        n=rd(),m=rd();  
        for(int i=1;i<=m;++i) x=rd(),y=rd(),add(x,y);   
        for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);           
        for(int i=1;i<=n;++i) 
        {
            int u=idx[i];  
            for(int j=hd[i];j;j=nex[j]) 
            {
                y=to[j];    
                int v=idx[y];   
                if(u==v) continue;   
                if(!vis[u][v]) 
                {
                    vis[u][v]=1;         
                    G[u].push_back(v);  
                    ++deg[v];  
                }
            }
        } 
        for(int i=1;i<=scc;++i)  
        {
            if(!deg[i])  
            {
                f[i]=size[i];  
                q.push(i);  
            }
        }
        while(!q.empty()) 
        {
            int u=q.front(); q.pop();    
            for(int i=0;i<G[u].size();++i) 
            {
                int v=G[u][i];       
                --deg[v];  
                f[v]=max(f[v],f[u]+size[v]);    
                if(!deg[v]) q.push(v);  
            }
        }   
        int ans=0; 
        for(int i=1;i<=scc;++i) ans=max(ans,f[i]);       
        printf("%d
    ",ans);  
        // printf("%d
    ",clock()-T);   
        return 0; 
    }
    

      

    Task 3 顺利 luck.cpp/in/out   

    题意:给定一棵有根树,每个点都有种颜色,有两个操作:  

    1. 修改一个点的颜色

    2. 查询一个点子树中不同颜色种类数.      

    直接用带修改莫队+树状数组维护就好了.  

    时间复杂度为 $O(n^{frac{5}{3}} log n ).$  

    但是这是极限复杂度,而且树状数组的 log 非常小,所以跑的飞快.   

    总结:算是本场考试稍微有点难度的题,但是一眼就能看出是带修改莫队+树状数组维护,难度其实也不大.  

    code: 

    #include <cstdio> 
    #include <ctime>  
    #include <cstring> 
    #include <algorithm>    
    #include <map> 
    #include <stack> 
    #include <queue>  
    #include <vector>  
    #define N 1000009 
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)  
    using namespace std;    
    int n,m; 
    stack<int>S;  
    queue<int>q;  
    map<int,int>vis[N];  
    vector<int>G[N];  
    int low[N],dfn[N],idx[N],size[N],tim,scc;   
    int hd[N],to[N],nex[N],deg[N],f[N],edges;     
    void add(int u,int v) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
    }     
    void tarjan(int x) 
    { 
        S.push(x),dfn[x]=low[x]=++tim;  
        for(int i=hd[x];i;i=nex[i]) 
        {
            int y=to[i];   
            if(!dfn[y]) 
            {
                tarjan(y);  
                low[x]=min(low[x],low[y]);  
            }
            else if(!idx[y]) low[x]=min(low[x],dfn[y]);   
        }     
        if(dfn[x]==low[x]) 
        {
            ++scc;  
            for(;;) 
            {
                int u=S.top(); S.pop();  
                idx[u]=scc;   
                ++size[scc];  
                if(u==x) break;  
            }
        }
    }
    char *p1,*p2,buf[100000];  
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)    
    int rd() 
    {
        int x=0; char c;  
        do { c=nc(); } while(c<48);                   
        while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();   
        return x;   
    }
    int main() 
    { 
        // setIO("good");                
        int x,y,z; 
        n=rd(),m=rd();  
        for(int i=1;i<=m;++i) x=rd(),y=rd(),add(x,y);   
        for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);           
        for(int i=1;i<=n;++i) 
        {
            int u=idx[i];  
            for(int j=hd[i];j;j=nex[j]) 
            {
                y=to[j];    
                int v=idx[y];   
                if(u==v) continue;   
                if(!vis[u][v]) 
                {
                    vis[u][v]=1;         
                    G[u].push_back(v);  
                    ++deg[v];  
                }
            }
        } 
        for(int i=1;i<=scc;++i)  
        {
            if(!deg[i])  
            {
                f[i]=size[i];  
                q.push(i);  
            }
        }
        while(!q.empty()) 
        {
            int u=q.front(); q.pop();    
            for(int i=0;i<G[u].size();++i) 
            {
                int v=G[u][i];       
                --deg[v];  
                f[v]=max(f[v],f[u]+size[v]);    
                if(!deg[v]) q.push(v);  
            }
        }   
        int ans=0; 
        for(int i=1;i<=scc;++i) ans=max(ans,f[i]);       
        printf("%d
    ",ans);   
        return 0; 
    }
    

      

    总结:虽说题的难度不大,但是自己 AK 了还是蛮开心的.  

  • 相关阅读:
    洛谷P3313&BZOJ-3531【SDOI2014】旅行--线段树动态开点+树链剖分
    BZOJ3932【CQOI2015】任务查询系统&洛谷P3168--主席树区间前K小+差分
    博客中的代码CE说明
    栗栗的书架--洛谷P2468【SDOI2010】&BZOJ 1926二分+前缀和+主席树
    hdu1010--Tempter of the Bone(迷宫)
    hdu1242 Rescue DFS(路径探索题)
    hdu 1241--入门DFS
    注意引用的用法
    划分树---hdu4417---区间查找(不)大于h的个数
    程序员能力矩阵
  • 原文地址:https://www.cnblogs.com/guangheli/p/13140715.html
Copyright © 2011-2022 走看看