第九届湖南省大学生程序设计竞赛部分题解

前言:这套题目到处都找不到,csu上面也提交不了。最后在湖南师大oj找到了,可是这个师大oj实在是不好用,每次提交都要重新登录不说,还不支持lld,还我浪费好多时间去改WA。



思路:数据量比较小,直接暴力求解即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
char s[1050];
int pos[1050];
int check(int b,int t,int k)
{
    int num=0,l=b,r=t;
    for(int i=b; i<=t; i++)
    {
        if(s[l]!=s[r]) num++;
        if(num>2*k) return 0;
        l++;
        r--;
    }
    return 1;
}
int main()
{
    int k;
    int tot=1;
    while(~scanf("%d",&k))
    {
        getchar();
        gets(s);
        int len=strlen(s),t=0;
        for(int i=0; i<len; i++)
            if(s[i]>='a'&&s[i]<='z')
            {
                pos[t]=i;
                s[t++]=s[i];
            }
            else if(s[i]>='A'&&s[i]<='Z')
            {
                pos[t]=i;
                s[t++]=s[i]-'A'+'a';
            }
        int ans=1,id=0;
        for(int i=0; i<t; i++)
        {
            for(int j=i+1; j<t; j++)
            {
                if(pos[j]-pos[i]+1<=ans) continue;
                if(check(i,j,k))
                {
                    ans=pos[j]-pos[i]+1;
                    id=pos[i];
                }
            }
        }
        printf("Case %d: %d %d\n",tot++,ans,id+1);
    }
    return 0;
}


思路:细心模拟题,数组模拟链表的操作即可,第三个操作极其麻烦,要细心点。

对于第四个操作,其实注意x和y是原序列的下标,所以序列反了和没反对于1,2操作只是x插在y的左右反向反了而已,第三个操作就无影响了

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 100050
struct Node
{
    int qian,hou;
} p[N];
void init(int n)
{
    p[1].qian=-1;
    p[n].hou=-1;
    for(int i=2; i<=n; i++)
        p[i].qian=i-1;
    for(int i=1; i<n; i++)
        p[i].hou=i+1;
}

int main()
{
    int n,m,x,y,l;
    int tot=1;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        init(n);
        int num=0;
        while(m--)
        {
            scanf("%d",&l);
            if(l==4) num++;
            else
            {
                if(num&1&&l<3) l=3-l;
                if(l==1)
                {
                    scanf("%d %d",&x,&y);
                    if(p[y].qian==x) continue;
                    int px=p[x].qian,py=p[y].qian;
                    int hx=p[x].hou,hy=p[y].hou;
                    if(px!=-1) p[px].hou=hx;
                    if(hx!=-1) p[hx].qian=px;
                    p[x].qian=p[y].qian;
                    p[x].hou=y;
                    p[y].qian=x;
                    if(py!=-1) p[py].hou=x;
                }
                else if(l==2)
                {
                    scanf("%d %d",&x,&y);
                    if(p[y].hou==x) continue;
                    int px=p[x].qian,py=p[y].qian;
                    int hx=p[x].hou,hy=p[y].hou;
                    if(px!=-1) p[px].hou=hx;
                    if(hx!=-1) p[hx].qian=px;
                    p[x].hou=p[y].hou;
                    p[x].qian=y;
                    p[y].hou=x;
                    if(hy!=-1) p[hy].qian=x;
                }
                else if(l==3)
                {
                    scanf("%d %d",&x,&y);
                    int px=p[x].qian,py=p[y].qian;
                    int hx=p[x].hou,hy=p[y].hou;
                    if(px==y)
                    {
                        p[x].qian=p[y].qian;
                        p[y].hou=p[x].hou;
                        if(py!=-1) p[py].hou=x;
                        if(hx!=-1) p[hx].qian=y;
                        p[y].qian=x;
                        p[x].hou=y;
                    }
                    else if(py==x)
                    {
                        p[y].qian=p[x].qian;
                        p[x].hou=p[y].hou;
                        if(px!=-1) p[px].hou=y;
                        if(hy!=-1) p[hy].qian=x;
                        p[x].qian=y;
                        p[y].hou=x;
                    }
                    else
                    {
                        p[x].qian=py;
                        p[y].qian=px;
                        p[x].hou=hy;
                        p[y].hou=hx;
                        if(px!=-1) p[px].hou=y;
                        if(hx!=-1)p[hx].qian=y;
                        if(py!=-1) p[py].hou=x;
                        if(hy!=-1) p[hy].qian=x;
                    }
                }
            }
        }
        long long ans=0;
        if(num&1)
        {
            int head;
            for(int i=1; i<=n; i++)
                if(p[i].hou==-1)
                {
                    head=i;
                    break;
                }
            while(head!=-1)
            {
                ans+=head;
                head=p[head].qian;
                if(head!=-1) head=p[head].qian;
            }
        }
        else
        {
            int head;
            for(int i=1; i<=n; i++)
                if(p[i].qian==-1)
                {
                    head=i;
                    break;
                }
            while(head!=-1)
            {
                ans+=head;
                head=p[head].hou;
                if(head!=-1) head=p[head].hou;
            }
        }
        printf("Case %d: %I64d\n",tot++,ans);
    }
    return 0;
}


思路:直接比较即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
char str[50][10];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=5;i++){
        scanf("%s",str[i]+1);
    }
    int ans[20],id = 0;
    for(int i=1;i<=n;i++){
        bool flag = false;
        for(int j=4*(i-1)+1;j<=4*i&&!flag;j++){
            printf("%d %d\n",4*(i-1)+1,4*i);
            if(str[1][j]=='*'){
                flag = true;
                if(str[2][j]!='.') ans[++id] = 1;
                else if(str[4][j]!='*') ans[++id] = 3;
                else ans[++id] = 2;
            }
        }
    }
    for(int i=1;i<=id;i++){
        printf("%d",ans[i]);
    }
    printf("\n");
    return 0;
}



题意:有n个城市和m条路,现在要从s到t,保证可以走到

所以得路都有一个通过时间,但是路本身会开启a时间,关闭b时间这样反复循环,求从s到t的最短时间

思路:一开始以为很复杂,其实就是一个最短路的问题,只不过加了点限制而已,不会影响s到t的最短距离。

用dijkstra或者spfa都可以

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define INF 999999999
struct Edge
{
    int v,next;
    int a,b,t;
} edge[50050];
int cnt,head[305];
int n,m,s,e;
int vis[305],d[305];
void addedge(int u,int v,int a,int b,int t)
{
    edge[cnt].v=v,edge[cnt].a=a,edge[cnt].b=b,edge[cnt].t=t;
    edge[cnt].next=head[u],head[u]=cnt++;
}
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
}
void spfa()
{
    for(int i=1; i<=n; i++)
        d[i]=INF;
    memset(vis,0,sizeof(vis));
    d[s]=0;
    vis[s]=1;
    queue<int>que;
    que.push(s);
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        vis[now]=0;
        for(int i=head[now]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v,a=edge[i].a,b=edge[i].b,t=edge[i].t;
            int p=d[now]%(b+a),dis;
            if (p>a) dis=d[now]+a+b-p+t;
            else if(a-p<t) dis=d[now]+a+b-p+t;
            else dis=d[now]+t;
            if(d[v]>dis)
            {
                d[v]=dis;
                if(!vis[v])
                {
                    que.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}
int main()
{
    //freopen("f.in","r",stdin);
    //freopen("f.txt","w",stdout);
    int u,v,a,b,t;
    int tot=1;
    while(scanf("%d %d %d %d",&n,&m,&s,&e)!=EOF)
    {
        init();
        while(m--)
        {
            scanf("%d %d %d %d %d",&u,&v,&a,&b,&t);
            if(t>a) continue;
            addedge(u,v,a,b,t);
        }
        spfa();
        printf("Case %d: %d\n",tot++,d[e]);
    }
    return 0;
}







思路:对于某个位置只要往左右两边找到最近的名字,比较一下距离即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 105;
int n,m,L[maxn],R[maxn];
char str[maxn][5];

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
        scanf("%s",str[i]);

    memset(L,-1,sizeof(L));
    memset(R,-1,sizeof(R));
    for(int i = 1; i <= n; i++)
        if(str[i][0] != '?')
            L[i] = i;
        else L[i] = L[i-1];
    for(int i = n; i >= 1; i--)
        if(str[i][0] != '?')
            R[i] = i;
        else R[i] = R[i+1];
    scanf("%d",&m);
    while(m--)
    {
        int k;
        scanf("%d",&k);
        if(str[k][0] != '?') printf("%s\n",str[k]);
        else
        {
            if(L[k] == -1)
            {
                int cnt = R[k] - k + 1;
                for(int i = 1; i < cnt; i++)
                    printf("left of ");
                printf("%s\n",str[R[k]]);
                continue;
            }
            if(R[k] == -1)
            {
                int cnt = k - L[k] + 1;
                for(int i = 1; i < cnt; i++)
                    printf("right of ");
                printf("%s\n",str[L[k]]);
                continue;
            }
            if(k - L[k] + 1 == R[k] - k + 1)
                printf("middle of %s and %s\n",str[L[k]],str[R[k]]);
            else if(k - L[k] + 1 < R[k] - k + 1)
            {
                int cnt = k - L[k] + 1;
                for(int i = 1; i < cnt; i++)
                    printf("right of ");
                printf("%s\n",str[L[k]]);
            }
            else if(k - L[k] + 1 > R[k] - k + 1){
                int cnt = R[k] - k + 1;
                for(int i = 1; i < cnt; i++)
                    printf("left of ");
                printf("%s\n",str[R[k]]);
            }
        }
    }
    return 0;
}


思路:每一次涨潮其实就是树状数组的一次区间变化,那么我们每次都去区间更新,最后求值即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100005;
int n,m,k,tree[maxn<<1];
int h[maxn];

int lowbit(int x)
{
    return x & -x;
}

void update(int x,int d)
{
    while(x <= n)
    {
        tree[x] += d;
        x += lowbit(x);
    }
}

int sum(int x)
{
    int ans = 0;
    while(x > 0)
    {
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}

int main()
{
    int a,b,cas = 1;
    while(scanf("%d %d %d",&n,&m,&k)!=EOF)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d",&h[i]);
        memset(tree,0,sizeof(tree));
        sort(h+1,h+1+n);
        int pre = 1;
        while(m--)
        {
            scanf("%d %d",&a,&b);
            int pos = lower_bound(h+1,h+1+n,1 + a) - h;
            update(pre,1);
            update(pos,-1);
            pre = lower_bound(h+1,h+1+n,b+1) - h;
        }
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int cnt = sum(i);
            if(cnt >= k)
                ans++;
        }
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}


题意:给两个数x,y

再给一个3*10的矩阵,第一行表示在数的末尾加上0~9所需要的花费

第二行表示当前数加上0~9所需要的花费

第三行表示当前数*0~9所需要的花费

问从x->y的最小花费,以及在最小花费的情况下的最小操作次数

思路:dp[i]表示凑到i这个数所需要的最小花费,三重循环去转移即可。

转移的过程中用一个num数组去记录最小操作次数即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int inf = 999999999;
int n,m;
int cost[4][10];
int dp[100005],num[100005];

int main()
{
    int cas = 1;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i = 1; i <= 3; i++)
            for(int j = 0; j <= 9; j++)
                scanf("%d",&cost[i][j]);
        for(int i = 0; i <= m; i++)
            dp[i] = num[i] = inf;
        dp[n] = 0;
        num[n] = 0;
        if(n != 0)
        {
            dp[0] = cost[3][0];
            num[0] = 1;
        }
        for(int k = 0; k <= m; k++)
            for(int i = 1; i <= 3; i++)
                for(int j = 0; j <= 9; j++)
                {
                    if(i == 1)
                    {
                        int tmp = k % 10;  //取出个位
                        if(tmp != j) continue;
                        tmp = k / 10;
                        if(dp[k] > dp[tmp] + cost[i][j])
                        {
                            dp[k] = dp[tmp] + cost[i][j];
                            num[k] = num[tmp] + 1;
                        }
                        else if(dp[k] == dp[tmp] + cost[i][j])
                            num[k] = min(num[k],num[tmp]+1);
                    }
                    else if(i == 2)
                    {
                        int tmp = k - j;
                        if(tmp < 0) continue;
                        if(dp[k] > dp[tmp] + cost[i][j])
                        {
                            dp[k] = dp[tmp] + cost[i][j];
                            num[k] = num[tmp] + 1;
                        }
                        else if(dp[k] == dp[tmp] + cost[i][j])
                            num[k] = min(num[k],num[tmp]+1);
                    }
                    else
                    {
                        if(j == 0) continue;
                        if(k % j == 0)
                        {
                            int tmp = k / j;
                            if(dp[k] > dp[tmp] + cost[i][j])
                            {
                                dp[k] = dp[tmp] + cost[i][j];
                                num[k] = num[tmp] + 1;
                            }
                            else if(dp[k] == dp[tmp] + cost[i][j])
                                num[k] = min(num[k],num[tmp]+1);
                        }
                    }
                }
        printf("Case %d: %d %d\n",cas++,dp[m],num[m]);
    }
    return 0;
}


思路:直接暴力枚举a和b即可

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
    long long x,y;
    int tot=1;
    while(scanf("%I64d %I64d",&x,&y)!=EOF)
    {
        long long ans=0;
        for(long long i=x; i*i*i<=y*10+3; i++)
        {
            for(long long j=i; j*j*j<=y*10+3; j++)
            {
                long long m=i*i*i+j*j*j;
                if(m%10==3&&m/10>=x&&m/10<=y)
                    ans++;
            }
        }
        printf("Case %d: %I64d\n",tot++,ans*2);
    }
    return 0;
}






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值