2017年西南民族大学程序设计竞赛-网络同步赛

Posted Roni

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017年西南民族大学程序设计竞赛-网络同步赛相关的知识,希望对你有一定的参考价值。

题目描述

 
现在有一个N*M的矩形星图。其中包括恒星和黑洞。恒星可以向上、下、左、右发射光束,且允许光束从其中穿过;黑洞会吸收所有经过的光束。
若一颗恒星向上、下、左、右发射光束,你能告诉我,该光束能否避免被黑洞吸收,进入星图之外的区域么?

输入描述:

单组输入。第一行三个正整数N,M,Q(1 <= N,M
<= 1000,1 <= Q <= 1000000),分别表示矩阵的行列,以及询问的个数,询问之间相互独立。
然后一个N*M的矩阵,由’*’和’#’构成,表示星图。’*’表示恒星,’#’表示黑洞。
最后Q行,表示Q个询问,每行两个正整数x,y(1 <= x <= N, 1 <= y
<= M)表示发光恒星的位置(从上往下数第x行,从左往右数第y列,且保证该位置一定是恒星)和一个字符p(p∈{‘L’, ‘R’,
‘D’, ‘U’},’R’表示向右;’L’表示向左;’D’表示向下’;’U’表示向上)表示该恒星产生光束的方向。

输出描述:

一共Q行。对于每个询问,若该恒星发出的光束能够进入星图之外的区域则输出“YES”;否则输出“NO”。(不包含引号)
示例1

输入

4 5 5
**##*
*****
*#*#*
##**#
2 3 D
2 3 U
1 5 R
4 4 U
3 1 U

输出

YES
NO
YES
NO
YES
【二维前缀和】:注意用%s输入字符,%c吃回车。记得用sca不用cin,因为询问次数多。
技术分享图片
/*设黑洞的只为1 其他为0  预处理出每一行每一列的前缀和
然后查询的时候根据方向去判断某一段的和是否大于零
*/
#include<bits/stdc++.h>
#define ll long long;
using namespace std;
char s[1007][1007];
int a[1007][1007];
int b[1007][1007];
int num[1007][1007];
int main()
{
    int n,m,q,ans=0;
    int x,y;
    char c[10];
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]==*)
                num[i][j]=0;
            else
                num[i][j]=1;
        }
    }

    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)//记录矩阵a中第i行第1个数到第j个数的和
        {
            a[i][j]=a[i][j-1]+num[i][j];
        }
    }

    for(int j=1;j<=m;j++)//b[i][j]记录矩阵b中第j列第1个数到第i个数的和
        for(int i=1;i<=n;i++)
            b[i][j] = b[i-1][j]+num[i][j];
    while(q--)
    {
        scanf("%d%d%s",&x,&y,&c[0]);//不要用%c 会读回车
        if(c[0]==U)
        {
            if(b[x][y]==0) puts("YES");
            else puts("NO");
        }

        if(c[0]==D)
        {
            if(b[n][y]-b[x][y]==0) puts("YES");
            else puts("NO");
        }

        if(c[0]==L)
        {
            if(a[x][y]==0) puts("YES");
            else puts("NO");
        }

        if(c[0]==R)
        {
            if(a[x][m]-a[x][y]==0) puts("YES");
            else puts("NO");
        }

    }

}
View Code

 

题目描述

我们定义“好数”:对于一个正整数,若它只有0~9中的一种数字构成,我们就称其为好数。现在给你一个正整数,请判断它是否为好数。

输入描述:

单组输入。一个正整数x(1<=  x <= 10100000)

输出描述:

若该数x是“好数”则输出“YES”。否则输出“NO”。(没有双引号)
示例1

输入

7777777777777777777777777777777777777888888888888888

输出

NO
示例2

输入

5555555555555555555555555555555555555555

输出

YES
示例3

输入

16146483543484318146436841468

输出

NO
【set判重】:
技术分享图片
#include<bits/stdc++.h>
using namespace std;
string s;
set<int> st;
int main()
{
    cin>>s;
    for(int i=0;s[i];i++)
    {
        st.insert(s[i]-0);
    }
    if(st.size()==1)
        puts("YES");
    else
        puts("NO");
    return 0;
}
STL

 

题目描述

自从ZZZZone吃完糖果后,他开始改吃巧克力了,他每天想吃n个巧克力增在甜蜜值,他决定早上吃K个巧克力,晚上吃n - K个巧克力,每个巧克力在早上吃和在晚上吃的甜蜜值是不一样的,他想让自己得到的甜蜜值最大,并想知道最大是多少。
请你编程帮助他。

输入描述:

第一行包含两个数n,K表示每天要吃的巧克力数量和要在早上吃的数量。(n <= 100000, K <= n)
第二行包含n个整数Ai(1 <= i <= n) 表示个第i个巧克力在早上吃可得到的甜蜜值 (Ai <= 100000)
第三行包含n个整数Bi(1 <= i <= n) 表示个第i个巧克力在晚上吃可得到的甜蜜值 (Bi <= 100000)

输出描述:

输出仅一行包含一个整数表示ZZZZone能获得的最大甜蜜值。
示例1

输入

2 1
3 6
2 8

输出

11

说明

早上吃第一个巧克力得到3甜蜜值,晚上吃第2个巧克力得到8的甜蜜值,所以最大可得到11的甜蜜值。
【理解题意】:
技术分享图片
#include<bits/stdc++.h>
using namespace std;
struct A{
    int x,y;
}a[100010];
int cmp(const struct A a,const struct A b)
{
    return a.x-a.y>b.x-b.y;
}
int main()
{
    
    int i,n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(i=0;i<n;i++)
            scanf("%d",&a[i].x);
        for(i=0;i<n;i++)
            scanf("%d",&a[i].y);
        sort(a,a+n,cmp);
        long long sum=0;
        for(i=0;i<n;i++)
            if(i<k)
                sum+=a[i].x;
            else
                sum+=a[i].y;
        printf("%lld\n",sum);
    }
    return 0;
}
结构体排序

 

题目描述

ZZZZone是一个特别喜欢甜食的人。有一天,他得到了n个糖果盒子,每个盒子里都有无穷个糖果,每个盒子里的糖果都有固定的甜蜜值。
为了获得更多的甜蜜值,ZZZZone列出了m个方案:每个方案中都有一个L 、R,ZZZZone会从第L个盒子到第R个盒子这连续的R - L + 1 个盒子中,每个盒子里拿出一颗糖吃掉,来获得甜蜜值。
每个方案最多只能实现一次,当然也可以不实现,那么,ZZZZone可以获得的最大甜蜜值是多少?
 

输入描述:

第一行,一个整数n,表示有n个糖果盒子 (n <= 10000)
第二行包含n个整数,表示从下标为1到n的盒子的甜蜜值(-10000 <= wi <= 10000)
第三行包含一个整数m表示方案数 (m <= 10000)
接下来m行,每行两个整数L, R (1 <= L, R <= n)

输出描述:

输出一行,包含一个整数表示最大的甜蜜值.
示例1

输入

5
1 -2 3 -4 5
2
1 5
1 2

输出

3

说明

第一个方案从1到5可得到3的甜蜜值,第二个可以得到-1的甜蜜值(此时当然不会选这个方案),所以最大可得到3的甜蜜值
【区间差分】:
技术分享图片
#include<bits/stdc++.h>

using namespace std;
#define ll long long
int main()
{
    ll sum[10005],a[10005];
    int n,q,l,r;
    ll tot,ans;
    tot=ans=0;
    scanf("%d",&n);
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&l,&r);
        if(sum[r]-sum[l-1]>0)
            ans+=sum[r]-sum[l-1];
    }
    printf("%lld\n",ans);
    return 0;
}
前缀和/差分

 

题目描述

一天小明同学拿着m种颜色的油漆去涂刷n块格子,在涂刷的过程中他发现有很多种涂色方案,并很快的算出了答案,然后他发现如果涂好颜色的格子中只要存在某两个相邻的格子颜色一样,他就会感到开心,他想知道有多少种让他开心的涂刷方案。

输入描述:

输入仅包含一行,包含两个数n,m分别表示格子数和颜色数。(1 <= n <= 1e12, 1 <= m <= 1e12)

输出描述:

输出一行包含一个整数,让小明开心的涂刷方案数。 答案对1000000007取模
示例1

输入

3 2

输出

6

说明

一共有(1, 1, 2), (2, 1, 1), (2, 2, 1), (1, 2, 2), (1, 1, 1), (2, 2, 2) 这6种方案
【逆向思维/组合数学】:总数-求不会两两相同的情况数。取模后可能比后面的小,可能会产生负数,取模的时候注意下,但是边计算便内部取模是必须的。
技术分享图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pi;
typedef pair<ll, ll> pl;
const int N = 1e5+5;
int a[N];
const int mod = 1000000007;
ll qpow(ll a, ll b) {
    ll res = 1;
    a %= mod;
    while(b) {
        if(b&1) res = res*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return res;
}
int main() {
    ll n, m;
    scanf("%lld %lld", &n, &m);
    ll ans = qpow(m, n);
    ans -= m%mod*qpow(m-1, n-1)%mod;
    ans = ans%mod;
    ans = (ans+mod)%mod;
    printf("%lld\n", ans);
    return 0;
}
组合数学/逆向思维

 

题目描述

    饿了很久的XzzF终于忍不住了,出去找了一份兼职。他来到一个射击训练营,他的工作呢,就是数那些运动员打的靶子,然后把运动员的数据报给主教练,方便主教练选出优秀的运动员出去参加比赛。
    数靶这个活儿吧!显然是计件的,简单来说就是数的多,报酬就越高。XzzF想写个程序来做数靶这件事,不仅快,而且报酬高,岂不很nice!
    靶子可以看做是一个13*13的矩阵,相应的环数对应矩阵里的某些区域,如下图所示:
                            
                        1 1 1 1 1 1 1 1 1 1 1 1 1
                        1 2 2 2 2 2 2 2 2 2 2 2 1
                        1 2 2 2 2 2 2 2 2 2 2 2 1
                        1 2 2 3 3 3 3 3 3 3 2 2 1
                        1 2 2 3 3 3 3 3 3 3 2 2 1
                        1 2 2 3 3 4 4 4 3 3 2 2 1
                        1 2 2 3 3 4 4 4 3 3 2 2 1
                        1 2 2 3 3 4 4 4 3 3 2 2 1
                        1 2 2 3 3 3 3 3 3 3 2 2 1
                        1 2 2 3 3 3 3 3 3 3 2 2 1
                        1 2 2 2 2 2 2 2 2 2 2 2 1 
                        1 2 2 2 2 2 2 2 2 2 2 2 1
                        1 1 1 1 1 1 1 1 1 1 1 1 1
 
    而运动员所打的靶,则看做一个13 * 13的且只包含 ‘.‘ 和 ‘#‘ 字符矩阵,‘#‘表示被击中,而 ‘.‘ 则表示没被击中。
    现在XzzF知道运动员射击的次数N,以及射击后的靶子。(详情可见样例)主教练想知道运动员的平均射击环数(保留两位小数)。
    然而XzzF已经饿到大脑不能正常工作了,所以,请你完成这个数靶程序。
 

输入描述:

第一行一个整数N(1 <= N <= 169),表示射击的次数,接着输入一个13 * 13的字符矩阵,里面只包含 ‘.‘ 和 ‘#‘,‘#‘表示被击中,而 ‘.‘ 则表示没被击中。(保证‘#‘恰好有N个)
多组输入,N=0表示输入结束。

输出描述:

该运动员的平均射击环数(保留两位小数)。
示例1

输入

2
.............
.............
.............
.............
.............
.............
......#......
...#.........
.............
.............
.............
.............
.............
0

输出

3.50

说明

射中3环一次,4环一次,平均值为3.50。
【模拟/规律】:
技术分享图片
#include <bits/stdc++.h>
using namespace std;
int getscore(int i, int j) {
    if(i >= 5 && i <= 7 && j >= 5 && j <= 7) return 4;
    if(i >= 3 && i <= 9 && j >= 3 && j <= 9) return 3;
    if(i >= 1 && i <= 11 && j >= 1 && j <= 11) return 2;
    else return 1;
}
char maps[13][13];
int n;
int main(void) {
    while(cin >> n && n) {
        int cnt = 0;
        for(int i = 0; i < 13; ++i) {
            cin >> maps[i];
            for(int j = 0; j < 13; ++j) {
                if(maps[i][j] == #)
                    cnt += getscore(i, j);
            }
        }
        printf("%.2f\n", (double)cnt / (double)n);
    }
}
规律

 

技术分享图片
#include<bits/stdc++.h>
using namespace std;

int a[13][13]=
{
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
        1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
        1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 4, 4, 4, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 4, 4, 4, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 4, 4, 4, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1,
        1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1,
        1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
        1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
char str[13][13];
int main()
{
    int n, i, j;
    while(scanf("%d",&n)&&n)
    {
        memset(str,0,sizeof(str));
        double sum=0;
        for (i=0; i<13; i++)
            scanf("%s",str[i]);
        for (i=0; i<13; i++)
            {
                for (j=0; j<13; j++)
                    {
                        if(str[i][j]==#)sum+=a[i][j];
                    }
            }
        printf("%.2lf\n",1.0*sum/n);
    }
 
    return 0;
}
暴力/鲁棒性不足

 

题目描述

中国文化的五行:金、木、水、火、土相生相克, 一天Alice和Bob玩起了卡牌游戏。卡牌包含5种类型Jin,Mu,Shui,Huo,Tu,分别代表金、木、水、火、土。

金克木,木克土,土克水,水克火,火克金。游戏规则如下:

两人玩n轮,每轮各自抽取一张卡牌,如果其中一个人的牌克制另一个人的牌那么这个人得3分,另一个人得0分。没有克制关系两人都得1分。最后得分高的获胜。

输入描述:

第一行包含一个整数n(1 <= n <= 1000),表示两人游戏轮数。
接下来n行包含两个字符串,分别表示Alice,Bod抽到的卡牌类型
(本题为单组测评)

输出描述:

输出仅一行,如果Alice获胜输出“Alice”,Bob获胜输出“Bob”,平局输出“Draw”
(本题为单组测评)
示例1

输入

3 
Jin Mu
Mu Jin
Huo Huo

输出

Draw
【模拟】:
技术分享图片
#include<bits/stdc++.h>

using namespace std;
int n,n1,n2;
int main()
{
    string s1,s2;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        cin>>s1>>s2;
        if(s1=="Jin"&&s2=="Mu") n1+=3;
        else if(s2=="Jin"&&s1=="Mu") n2+=3;

        else if(s1=="Mu"&&s2=="Tu") n1+=3;
        else if(s2=="Mu"&&s1=="Tu") n2+=3;

        else if(s1=="Tu"&&s2=="Shui") n1+=3;
        else if(s2=="Tu"&&s1=="Shui") n2+=3;

        else if(s1=="Shui"&&s2=="Huo") n1+=3;
        else if(s2=="Shui"&&s1=="Huo") n2+=3;

        else if(s1=="Huo"&&s2=="Jin") n1+=3;
        else if(s2=="Huo"&&s1=="Jin") n2+=3;

        else continue;
    }
    if(n1>n2) puts("Alice");
    else if(n1==n2) puts("Draw");
    else puts("Bob");
}
暴力枚举
技术分享图片
#include <bits/stdc++.h>
using namespace std;
int a, b;
string s1, s2;
int getscore(char s1, char s2) {
    int a = 0;
    if(s1 == J && s2 == M) a = 3;
    else if(s1 == M && s2 == T) a = 3;
    else if(s1 == T && s2 == S) a = 3;
    else if(s1 == S && s2 == H) a = 3;
    else if(s1 == H && s2 == J) a = 3;
    else a = 1;
    return a;
}
int main(void) {
    std::ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n; cin >> n;
    while(n--) {
        cin >> s1 >> s2;
        a += getscore(s1[0], s2[0]);
        b += getscore(s2[0], s1[0]);
    }
    if(a > b) cout << "Alice" << endl;
    else if(a < b) cout << "Bob" << endl;
    else cout << "Draw" << endl;
}
用首字母区分(因为没有首字母相同的)

 

H(SB题,观察输入写输出,题干无用)

技术分享图片
#include<bits/stdc++.h>

using namespace std;
const int N = 1007;
int n,m;

int main()
{
    while(cin>>n){
    while(n--)
    {
        printf("gu...");
    }
    printf("\n");
    printf("The story is so boring. And I am so hungry!\n");
    }
    return 0;
}
View Code

 

题目描述

    XzzF最近过着吃土的日子,饿的神魂颠倒!突然看到有人在做美食节宣传,有好多好吃的,但想吃到这些好吃的可以不容易!得答对主办方出的题。
    现在XzzF拿到这样一道题:长度为N的01字符串,且满足以下条件的方案数有多少种?
        1、串中不能有两个或多个连续的0。
    例如,10、10101、11101是满足条件的,而00、10001、10010是不满足条件的。
    XzzF已经饿的神志不清了!显然没有力气回答这道题了,所以,你一定要帮XzzF吃上那些好吃的,不然就莫得了!

输入描述:

一个整数N(1 <= N <= 20)。

输出描述:

满足题目所述条件的方案数。
示例1

输入

1

输出

2
示例2

输入

2

输出

3

说明

有01、10、11三种满足条件的方案。
【找规律/斐波那契数列】:
技术分享图片
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int dp[22][2];
int main()
{
    int n;
    cin>>n;
    dp[1][1]=1,dp[1][0]=1;
    for(int i=2;i<=n;i++)
    {
        dp[i][0]=dp[i-1][1]; 
        dp[i][1]=dp[i-1][0]+dp[i-1][1];
    }
    cout<<dp[n][1]+dp[n][0]<<endl;
    return 0;
}
DP

 

技术分享图片
#include<stdio.h>
#include<string.h>
int main()
{
    int n, i;
    scanf("%d",&n);
    int a[n+1];
    a[0]=2;
    a[1]=3;
    for(i=2;i<=n;i++)
        a[i]=a[i-1]+a[i-2];
    printf("%d\n",a[n-1]);
    return 0;
}
斐波那契数列

题目描述

猪妈妈让佩奇练习打字, 她给了佩奇一篇只有小写字母的字符串S ( 1 <= |S| <= 105)。 但是佩奇记不住键盘字母的位置,只能看着键盘一个一个打。淘气的乔治趁佩奇不注意, 偷偷的换了键盘按键的位置。 乔治是这样操作的:乔治每次扣下来两个键帽, 并且将这两个键帽互换位置重新安回去, 乔治越玩越起劲,一直重复了m(1 <= m <= 105)次。请输出佩奇打完字后屏幕上显示的实际字符串。

输入描述:

第一行输入一个字符串S ( 1 <= |S| <= 105);
第二行输入一个数字m(1 <= m <= 105), 表示佩奇要操作m次。
之后有m行, 每行有两个字母 c1, c2 表示佩奇要把这两个键帽互换位置。

输出描述:

输出一行字符串, 即佩奇用乔治玩坏的键盘输出的实际字符串。
示例1

输入

helloworld
3
e o
h z
l p

输出

zoppewerpd

备注:

|S| 是字符串s长度
【模拟/map】:
技术分享图片
#include<bits/stdc++.h>
#define ll long long;
using namespace std;
char s[100005],ss[100005];
char a[2],b[2];
map<char,char> mp;

int main()
{
    int q;
    scanf("%s",s);
    scanf("%d",&q);
    for(int i=a;i<=z;i++) mp[i]=i;
    while(q--) {
    scanf("%s%s",&a[0],&b[0]);
    swap(mp[a[0]], mp[b[0]]);
   }
    for(int i=0;s[i];i++)
    {
        if(mp[s[i]])
            s[i]=mp[s[i]];
        else continue;
    }
    printf("%s\n",s);

}
STL-map

 

题目描述

TRDD开了一家免费WiFi体验店, 所有人都可以免费连接WiFi, 只有一个条件, 你要提前一天预约。今天,TRDD收到了n(1 <= n <=1000)个人的预约, 每个人有一个时间段[L, R] (1 <= L <= R <= 5000)表示这个人预约连接WiFi从L时刻到R时刻。 但是市面上只有一种路由器, 这种路由器单台最多能同时连接m(n <= 100)台设备, TRDD想要知道最少使用多少台路由器就能保证明天每个人都能连上WiFi。

输入描述:

第一行包含两个数n(1 <= n <=1000), m (1 <= m <= 100)表示今天有n个人预约, 以及路由单台最大连接个数m。
之后有n行, 第i行有两个数字 [L, R] (1 <= L <= R <= 5000) 表示第i个人预约连接WiFi的时间是从L到R。

输出描述:

输出一个数字表示TRDD最少需要开启的路由器的个数。
示例1

输入

4 1
1 5
2 7
3 4
6 9

输出

3
【题意理解/区间计数】:
技术分享图片
#include<bits/stdc++.h>
using namespace std;

const int maxn = 5007;
int a[maxn];
int n,m,l,r,ma,ans;

int main()
{
    scanf("%d%d",&n,&m);

    while(n--)
    {
        scanf("%d%d",&l,&r);
        for(int j=l;j<=r;j++)
        {
            a[j]++;
        }
    }

    for(int i=1;i<=5000+5;i++)
    {
        ma=max(ma,a[i]);
    }

    if(ma%m == 0) ans=ma/m;
    else ans=ma/m+1;
    printf("%d\n",ans);

}
区间计数

 

 



以上是关于2017年西南民族大学程序设计竞赛-网络同步赛的主要内容,如果未能解决你的问题,请参考以下文章

12.28西南民族大学第十一届程序设计竞赛(同步赛)

新年第一篇!西南民族大学第十届校赛(同步赛)

西南民族大学第十届校赛(同步赛)

西南民族大学第十届校赛(同步赛) D

第十八届西南科技大学ACM程序设计竞赛(同步赛)签到题 6题

西南民族大学 春季 2023 训练赛4