2019寒假训练赛03解题报告

这场比赛感觉。。。怎么说呢,WA、TLE、RE、MLE、PE、CE都有,做题十分钟,改BUG一小时(心情复杂)。

A - Replace To Make Regular Bracket Sequence CodeForces - 612C

题意:给你()、[]、{}、<>四种括号,任意左括号之间或者右括号之间都可以变换。现在给你一个括号组成的字符串,问使其中括号之间完全配对最少需要变换几次,若无法完全配对则输出-1。

题解:模拟,因为里层的括号一定优先配对,所以最少变换次数也就是从最里层开始配,按部就班来就好。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
stack<char>s;
int main()
{
    string x;
    while(cin>>x)
    {
        while(!s.empty()) s.pop();
        int n=x.length();
        int ans=0;
        for(int i=0;i<n;i++)
        {
            if(s.empty()) s.push(x[i]);
            else
            {
                if(x[i]==')'&&s.top()=='(')
                {
                    s.pop();
                }
                else if(x[i]==']'&&s.top()=='[')
                {
                    s.pop();
                }
                else if(x[i]=='}'&&s.top()=='{')
                {
                    s.pop();
                }
                else if(x[i]=='>'&&s.top()=='<')
                {
                    s.pop();
                }
                else if((x[i]==')'||x[i]==']'||x[i]=='}'||x[i]=='>')&&(s.top()=='('||s.top()=='{'||s.top()=='['||s.top()=='<'))
                {
                    ans++;
                    s.pop();
                }
                else
                {
                    s.push(x[i]);
                }
            }
        }
        if(s.empty())
        printf("%d\n",ans);
        else
        printf("Impossible\n");
    }
}

B - Pearls in a Row CodeForces - 620C
题意:给你一个序列,其中包含两个相同数字的子序列被称为好序列,问最多可以划分成几个好序列。

题解:模拟,这里两个相同的数字不一定是好序列的头和尾,因为所有好序列必须可以拼成最初的整个序列。这里我用map记录前面是否有相同数字,再用个数组存下好序列的尾,最后直接输出。

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
int a[1000000+10];
int ans[1000000+10];
map<int,bool>q;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        q.clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int m=0;
        for(int i=1;i<=n;i++)
        {
            if(q[a[i]])
            {
                m++;
                ans[m]=i;
                q.clear();
            }
            else
            {
                q[a[i]]=1;
            }
        }
        if(!m)
        {
            printf("-1\n");
        }
        else
        {
            printf("%d\n",m);
            int last=1;
            for(int i=1;i<=m;i++)
            {
                if(i==m)
                {
                    printf("%d %d\n",last,n);//边界是最后一个数字
                }
                else
                {
                    printf("%d %d\n",last,ans[i]);
                    last=ans[i]+1;
                }
            }
        }
    }
    return 0;
}

C - 排列2 HDU - 1716

题意:现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。

题解:四位数首先前面不能有0,其次卡片可能有重复所以要去重,这里我用的dfs+set去重

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
char a[100];
char b[100];
bool vis[100];
set<string>s;
set<string>::iterator it;
void dfs(int x)
{
    if(x>4)
    {
        string now="";
        for(int i=1;i<=4;i++)
        {
            now+=b[i];
        }
        s.insert(now);
        return;
    }
    for(int i=1;i<=4;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            b[x]=a[i];
            dfs(x+1);
            vis[i]=0;
        }
    }
}
int main()
{
    
    int t=0;
    while(cin>>a[1]>>a[2]>>a[3]>>a[4])
    {
        s.clear();
        if(a[1]=='0'&&a[2]=='0'&&a[3]=='0'&&a[4]=='0') break;
        t++;
        if(t!=1)
        {
            printf("\n");
        }
        sort(a+1,a+4+1);
        dfs(1);
        string now="0000";
        string last="0000";
        bool flag=0;
        for(it=s.begin();it!=s.end();it++)
        {
            now=*it;
            if(now[0]!='0')
            {
                if(now[0]!=last[0])
                {
                    if(!flag)
                    {
                        flag=1;
                    }
                    else
                    {
                        cout<<endl;
                    }
                }
                else
                {
                    cout<<" ";
                }
                cout<<now;
            }
            last=now;
        }
        printf("\n");
    }
    return 0;
}

D - Can you find it? HDU - 2141
题意:给你三个数字L、M、N接下来三行分别有L个、M个和N个数字,以下S组询问,问能否从三组数字中各选一个数字使和等于X,输出YES或者NO。

题解:二分,先将前两组数字两两相加,再在第三组数字中寻找能凑出X的数,每次询问复杂度L * M * logn。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[505],b[505],c[505];
int es[250000+10];
int main()
{
    int n,m,l;
    int t=0;
    while(scanf("%d%d%d",&n,&m,&l)!=EOF)
    {
        t++;
        printf("Case %d:\n",t);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=m;i++) scanf("%d",&b[i]);
        for(int i=1;i<=l;i++) scanf("%d",&c[i]);
        int r=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                r++;
                es[r]=a[i]+b[j];
            }
        }
        sort(es+1,es+r+1);
        int k;
        scanf("%d",&k);
        for(int i=1;i<=k;i++)
        {
            int x;
            scanf("%d",&x);
            bool flag=0;
            for(int j=1;j<=l;j++)
            {
                if(*lower_bound(es+1,es+r+1,x-c[j])==x-c[j])
                {
                    flag=1;
                    break;
                }
            }
            if(flag)
            {
                printf("YES\n");
            }
            else
            {
                printf("NO\n");
            }
        }
    }
}

E - Legal or Not [HDU - 3342]

题意:n个人,m组关系。A B表示A是B的上级,而且关系之间是相互传递的,比如A是B的上级,B是C的上级,那么A也是C的上级。但是如果A是B的上级,B是C的上级,而C又是A的上级,那么关系就矛盾了。现在问你关系是否矛盾。

题解:bfs找是否存在一个圈。

F - Ignatius and the Princess IV HDU - 1029

题意:给你N个数字,让你找出哪个数字出现在(n+1)/2次(该数字一定存在且唯一)。

题解:模拟,排序后直接找。

G - Can you solve this equation? HDU - 2199

给你一个数字Y,让你求8x^4 + 7x^3 + 2x^2 + 3x + 6 == Y的解,答案在0到100直接,没有则输出-1.。

题解:二分答案,注意精度问题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
double check(double mid)
{
    return 8*mid*mid*mid*mid+7*mid*mid*mid+2*mid*mid+3*mid+6;
}
double del(double y)
{
    double l=0,r=100;
    while(r-l>1e-7)
    {
        double mid=(l+r)/2;
        if(check(mid)<=y)
        {
            l=mid;
        }
        else
        {
            r=mid;
        }
    }
    return r;
}
int main()
{
    int t;
    scanf("%d",&t);
    double y;
    while(t--)
    {
        scanf("%lf",&y);
        if(y<check(0)||y>check(100))
        {
            printf("No solution!\n");
        }
        else
        {
            printf("%.4lf\n",del(y));
        }
    }
    return 0;
}

H - Ordering Tasks UVA - 10305

题意:有一些任务,其中A B表示A任务排在B任务前面,求可能存在的任务顺序。

题解:拓扑排序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int maxn=10000+10;
stack<int>s;
struct cc{
    int from,to;
}es[maxn];
int first[maxn],nxt[maxn];
bool vis[maxn];
bool pd[105][105];
int tot=0;
void build(int ff,int tt)
{
    es[++tot]=(cc){ff,tt};
    nxt[tot]=first[ff];
    first[ff]=tot;
}
int ru[maxn];
int ans[maxn];
int m;
int n,k;
void del()
{
    for(int i=1;i<=n;i++)
    {
        if(ru[i]==0&&!vis[i])
        {
            //puts("233");
            m++;
            ans[m]=i;
            s.push(i);
            vis[i]=1;
        }
    }
    while(!s.empty())
    {
        int u=s.top(); s.pop();
        for(int i=first[u];i;i=nxt[i])
        {
            int v=es[i].to;
            ru[v]--;
        }
    }

    if(m!=n)
    {
        del();
    }
}
int main()
{

    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0) break;
        tot=0;
        m=0;
        memset(nxt,0,sizeof(nxt));
        memset(vis,0,sizeof(vis));
        memset(pd,0,sizeof(pd));
        memset(first,0,sizeof(first));
        int x,y;
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&x,&y);

            if(!pd[x][y])
            {
                ru[y]++;
                build(x,y);
            }

        }
        del();
        for(int i=1;i<n;i++)
        {
            cout<<ans[i]<<" ";
        }
        cout<<ans[n]<<endl;
    }
    return 0;
}

I - I Can Guess the Data Structure! UVA - 11995

题意:给你一些操作 1 X表示插入X元素,2 Y表示弹出元素Y,问你能完成这些操作的数据结构是queue、stack、priority_queue的哪一种,如果满足一个以上输出not sure,一个都不满足输出impossible。

题解:直接用三个数据结构模拟,有可能出现数据结构为空依然弹出的操作,注意防止RE。

#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
queue<int>q1;
priority_queue<int>q2;
stack<int>q3;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        while(!q1.empty()) q1.pop();
        while(!q2.empty()) q2.pop();
        while(!q3.empty()) q3.pop();
        int flag1=1,flag2=1,flag3=1;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==1)
            {
                q1.push(y);
                q2.push(y);
                q3.push(y);
            }
            else
            {
                if(q1.empty()||q1.front()!=y) flag1=0;
                if(q2.empty()||q2.top()!=y) flag2=0;
                if(q3.empty()||q3.top()!=y)  flag3=0;
                if(!q1.empty()) q1.pop();
                if(!q2.empty()) q2.pop();
                if(!q3.empty()) q3.pop();
            }
        }
        if(flag1+flag2+flag3==1)
        {
            if(flag1==1)
            {
                printf("queue\n");
            }
            if(flag2==1)
            {
                printf("priority queue\n");
            }
            if(flag3==1)
            {
                printf("stack\n");
            }
        }
        if(flag1+flag2+flag3>1)
        {
            printf("not sure\n");
        }
        if(flag1+flag2+flag3<1)
        {
            printf("impossible\n");
        }
    }
}

J - 4 Values whose Sum is 0 UVA - 1152

题意:n行,每行四个数字,从四列中个取一个数字,使其和为零,问可以找出几组这样的数字。

题解:二分,前两列一组,后两列一组,两两相加,二分查找和为零。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long a[4005][5];
long long b[16000000+10];
int n;
int check(long long x)
{
    int l=1,r=n*n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(b[mid]<x)
        {
            l=mid+1;
        }
        else if(b[mid]>x)
        {
            r=mid-1;
        }
        else if(b[mid]==x)
        {
            //cout<<b[mid]<<endl;
            int sum=1;
            for(int i=mid+1;i<=n*n;i++)
            {
                if(b[i]==x)
                {
                    sum++;
                }
                else
                {
                    break;
                }
            }
            for(int i=mid-1;i>=1;i--)
            {
                if(b[i]==x)
                {
                    sum++;
                }
                else
                {
                    break;
                }
            }
            return sum;
        }
    }
    return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld%lld%lld",&a[i][1],&a[i][2],&a[i][3],&a[i][4]);
        }
        int m=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                m++;
                b[m]=a[i][1]+a[j][2];
            }
        }
        sort(b+1,b+m+1);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                long long now=a[i][3]+a[j][4];
                ans+=check(-now);
            }
        }
        printf("%d\n",ans);
        if(t!=0)
        {
            printf("\n");
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值