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 了还是蛮开心的.  

原文地址:https://www.cnblogs.com/guangheli/p/13140715.html