肇庆学院"菜鸟杯"程序设计竞赛2019(同步赛)(回顾补题)

这次比赛5/12,感觉还是实力不太行,几道题目感觉可以写但是没写出来,赛后看题解也补完了所有的题目。这里正式记录一下,方便以后的回顾。官方题解

A 解锁专家

传送门

找规律。藏头诗,根据诗的每个首字母可得到提示。同时还是个大数,使用Java解决

import java.util.Scanner;
import java.math.BigInteger;
public class Main {
    public static void main(String args[]) {
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()) {
            int n=scanner.nextInt();
            if(n==1)
                System.out.println(1);
            else {
                if(n==2)
                    System.out.println(2);
                else {
                    if(n==3) {
                        System.out.println(4);
                    } else {
                        BigInteger[] num = new BigInteger[101];
                        num[1]=BigInteger.ONE;
                        num[2]=BigInteger.valueOf(2);
                        num[3]=BigInteger.valueOf(4);
                        for(int i=4;i<=100;i++) {
                            num[i]=BigInteger.ZERO;
                            num[i]=BigInteger.valueOf(2).multiply(num[i-1]);
                            num[i]=num[i].subtract(num[i-3]);
                        }
                        System.out.println(num[n].mod(BigInteger.valueOf(433494437)));
                    }
                }
            }
        }
    }
}

B 麻烦的杰西

传送门

一开始以为求最长连续递增子序列,然后WA到自闭......因为不是递增的序列也可以,所以换种思路所以对于每个位置做一个记录。l[i]表示位置i往左能找到的 不小于当前位置高度的 最长连续的 最左端的位置。如何更新l[i],对于每个位置i,假设h[i]<=h[l[i]-1],说明最左端的左边位置高度不小于当前位置i的高度,所以l[i]就可以沿用l[i]-1的l[],即:l[i]=l[l[i]-1]。r[i]同理可得。这里是使用栈的特性进行记录序列的头和尾,遍历一遍即可

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1000005], h[1000005];
int main() {
    int n;
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &h[i]);
            a[i] = i;
        }
        stack<ll>st;
        h[0] = -1000;
        h[n + 1] = -999;
        st.push(0);
        ll ans = 0, t = 0;
        for (int i = 1; i <= n + 1; i++) {
            while (h[st.top()] > h[i]) {
                ll index = st.top();
                st.pop();
                ll cnt = a[i - 1] - a[st.top()];
                if (ans < cnt * h[index]) {
                    t = h[index];
                    ans = cnt * h[index];
                }
            }
            st.push(i);
        }
        printf("%lld %lld\n", t, ans);
    }
    return 0;
}

C 最大模数

传送门

这就直接贴题解了,简单来说枚举前几个数寻找规律,然后根据奇偶性判定输出不同结果
通过二项式定理列出n取1~5的情况:
图片说明
% a²后有:
图片说明
显然,对n为偶数的情况,结果都是2。对n为奇数的情况,结果为2 * n * a。
此时问题转化为 求2 * n * a % ( a² ) 的最大值。
初步判断,知道2 * n * a = a² 时n的取值,把n-1代入上式,结果就是最大值。
进一步,通过化简2 * n * a = a² ,可以得到 n = a / 2。 故需要再考虑a的奇偶性:
①、当 a 为奇数的时候
由于 2 * n * a = 2 * (a / 2) * a < a² , 所以不需要取n-1,此时Ra就是最大模数了。
最大模数就是 2 * ( a - 1 ) / 2 * a = a² - a 。
②、当 a 为偶数的时候
由于 2 * n * a = 2 * (a / 2) * a = a² , 此时Ra = 0,所以取n-1,即n = a / 2 - 1。
最大模数就是 2 * a * ( a / 2 - 1 ) = a² - 2 * a 。

#include<bits/stdc++.h>
using namespace std;
vector<int> p1,p2;
int main() {
    long long n;
    while(~scanf("%lld",&n)) {
        if(n%2==0)
            printf("%lld\n",n*n-2*n);
        else
            printf("%lld\n",n*n-n);
    }
    return 0;
}

D 米多利亚

传送门
对于这种字符串交换找最小字典序的字符串题目类型,需要先观察对于'0' , ' 1' , '2' 这三种字符哪一种是特殊的,特殊体现在就是在三者之间,只有自己才有的特性,发现相邻的 '01','10','12','21' 可以任意交换成 '10','01','21','12'。
也就是'1'字符可以和'0','2'任意交换,同时只有'0','2'两者之间是不可交换的。举个例子,'102' 可以交换成'012','021'。无论怎么交换'0'和'2'的相对位置都是不能改变的。所以答案就是,在所有'0','2'相对位置不变的情况下,把字符串中所有的'1’都放在第一个'2'前面。

#include<bits/stdc++.h>
using namespace std;
int main() {
    string s;
    while(cin>>s) {
        int numone=0;
        for(int i=0;i<s.length();i++) {
            if(s[i]=='1')
                numone++;
        }
        int start=0;
        while(s[start]!='2')
            start++;
        int numzero=0;
        for(int i=0;i<start;i++) {
            if(s[i]=='0')
                numzero++;
        }
        string ans="";
        while(numzero--)
            ans+="0";
        while(numone--)
            ans+="1";
        for(int i=start;i<s.length();i++) {
            if(s[i]=='2'||s[i]=='0')
                ans+=s[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}

E 一步两步是魔鬼的步伐

传送门

二分法求取最大最小值。这题比赛的时候好像出锅了,然后果断没看

#include<bits/stdc++.h>
using namespace std;
const int maxn=200011;
int L, N, M;
int a[maxn],vis[maxn];
bool check(int m) {
    int cnt=0, pre=0;
    for(int i=1; i<=N; ++i) vis[i]=0;
    for(int i=1; i<=N; ++i) {
        if(a[i]-pre<m) cnt++;
        else pre=a[i], vis[i]=1;
    }
    pre=L;
    for(int i=N; i; --i) {
        if(!vis[i]) continue;
        if(pre-a[i]<m) cnt++;
        else break;
    }
    return cnt<=M;
}
  
int main() {
    while(cin>>L>>N>>M) {
        for(int i=1; i<=N; ++i)
            scanf("%d",&a[i]);
        sort(a+1,a+1+N);
        int l=1, r=L+1;
        while(l<r) {
            int m=(l+r)/2;
            if(check(m)) l=m+1;
            else r=m;
        }
        printf("%d\n", l-1);
    }
}

F 参赛

传送门

暴力打表,计算出每种符合的情况

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
bool vis1[MAXN];
bool vis2[MAXN];
void init() {
    memset(vis1,false,sizeof(vis1));
    for(int i=1;i<=100;i++) {
        int temp=i*3;
        for(int j=1;j<=i;j++)
            vis1[temp+j]=true;
    }
    memset(vis2,false,sizeof(vis2));
    for(int i=1;i<=30;i++) {
        int temp=i*10;
        for(int j=1;j<=i;j++)
            vis2[temp+j]=true;
    }
}
int main() {
    init();
    int n;
    while(~scanf("%d",&n)) {
        if(vis1[n]) {
            if(vis2[n])
                puts("All");
            else
                puts("First");
        } else {
            if(vis2[n])
                puts("Second");
            else
                puts("No");
        }
    }
    return 0;
}

G 数数有多少个水坑

传送门

经典的求取联通块问题

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
int n,m;
int next1[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool vis[MAXN][MAXN];
int num[MAXN][MAXN];
void DFS(int x,int y) {
    for(int i=0;i<4;i++) {
        int x1=x+next1[i][0];
        int y1=y+next1[i][1];
        if(x1<0||x1>=n||y1<0||y1>=m)
            continue;
        else {
            if(vis[x1][y1]||num[x1][y1]==0)
                continue;
            else {
                vis[x1][y1]=true;
                DFS(x1,y1);
            }
        }
    }
}
int main() {
    while(~scanf("%d%d",&n,&m)) {
        memset(vis,false,sizeof(vis));
        memset(num,0,sizeof(num));
        getchar();
        for(int i=0;i<n;i++) {
            for(int j=0;j<m;j++) {
                char c;
                scanf("%c",&c);
                if(c=='j'||c=='e'||c=='s'||c=='i')
                    num[i][j]=1;
            }
            getchar();
        }
        int ans=0;
        for(int i=0;i<n;i++) {
            for(int j=0;j<m;j++) {
                if(num[i][j]&&!vis[i][j]) {
                    vis[i][j]=true;
                    DFS(i,j);
                    ans++;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

H 你相信爱情吗

传送门

初看以为约瑟夫环,细品一下发现哦原来还是GCD,可惜可惜

#include<bits/stdc++.h>
using namespace std;
int main() {
    int t;
    while(~scanf("%d",&t)) {
        while(t--) {
            long long n,m;
            scanf("%lld%lld",&n,&m);
            long long z=__gcd(n,m);
            long long temp=n/z;
            if(temp>=n)
                printf("%lld\n",temp);
            else
                puts("-1");
        }
    }
    return 0;
}

I 师姐我想要红包

传送门

师姐我也想要红包。哦实验室里我最老,那打扰了。这乍一看以为MST,细品发现,状压裸题。回去补知识点了可惜可惜

#include<bits/stdc++.h>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=1005;
typedef long long ll;
int n;
const int inf=0x3f3f3f3f;
struct points
{
    double x,y;
}a[15];
double getlen(int i,int j)
{
    return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
double dis[15][15];
double dp[1<<15][15];
int main()
{
    while(cin>>n) {
        a[0].x=0;a[0].y=0;
        for(int i=1;i<=n;++i)
            cin>>a[i].x>>a[i].y;
 
        for(int i=0;i<=n;++i)
            for(int j=i+1;j<=n;++j)
                dis[i][j]=dis[j][i]=getlen(i,j);
        n++;
        for(int i=0;i <= 1<<n;++i) {
            for(int j=0;j<=n;++j)
                dp[i][j]=inf;
        }
        dp[1][0]=0;
        for(int i=1;i< 1<<n;++i) {
            for(int j=0;j<n;++j)
            if(i>>j&1) {
                for(int k=0;k<n;++k) {
                    if((i^1<<j)>>k&1)
                        dp[i][j]=min(dp[i][j],dp[i^1<<j][k]+dis[k][j]);
                }
            }
        }
        double ans=inf;
        for(int i=0;i<n;++i)
            ans=min(ans,dp[(1<<n)-1][i]);
        printf("%.2f\n",ans);
    }
    return 0;
}

J 试试划水

传送门

老题型了,老解法了,直接贴代码

#include<bits/stdc++.h>
char ch[100000+5];
int num1[100000+5];
int num2[100000+5];
int main() {   
    int t;
    scanf("%d",&t);
    while(t--) {
        memset(num1,0,sizeof(num1));
        memset(num2,0,sizeof(num2));
        int len,ans=0;
        scanf("%s",ch); 
        len=strlen(ch);
        for(int i=len-1;i>=0;i--) {
            num2[i]=num2[i+1];
            if(ch[i]=='U')
                num2[i]++;
        }
        for(int i=0;i<len;i++) {
            if(i!=0)
                num1[i]=num1[i-1];
            if(ch[i]=='Z')
                num1[i]++;
        }
        long long cnt=0;
        for(int i=0;i<len;i++) {
            if(ch[i]=='Q')
                cnt+=num1[i]*num2[i];
        }
        printf("%lld\n",cnt);
    }
    return 0;
}

K 钟Sir的任务

传送门

考虑贪心,每次从右往左将较小的字符往左移即可。暴力模拟即可解决问题

#include<bits/stdc++.h>
using namespace std;
const int MAXN=111;
vector<int> p;
bool vis[MAXN];
int main() {
    int t;
    while(~scanf("%d",&t)) {
        while(t--) {
            memset(vis,false,sizeof(vis));
            int n;
            scanf("%d",&n);
            p.clear();
            p.resize(n);
            for(int i=0;i<n;i++)
                scanf("%d",&p[i]);
            if(n==1) {
                printf("%d\n",p[0]);
                continue;
            }
            int cnt=0,m=n-1,temp=n;
            while(temp--) {
                bool flag=false;
                for(int i=n-1;i>=0;i--) {
                    if(p[i]<p[i-1]&&!vis[i-1])
                        vis[i-1]=true,swap(p[i],p[i-1]),cnt++,flag=true;
                    if(cnt==m)
                        break;
                }
                if(!flag)
                    break;
                if(cnt==m)
                    break;
            }
            for(int i=0;i<n;i++) {
                if(i==0)
                    printf("%d",p[i]);
                else
                    printf(" %d",p[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

L JAVA_Xin的小心思

传送门

考虑贪心,先求取不压缩的值之和,然后按照压缩量排序,每次从大到小依次减去压缩量,直到符合条件为止。

#include<bits/stdc++.h>
using namespace std;
vector<long long> p;
int main() {
    int n;
    long long m;
    while(~scanf("%d%lld",&n,&m)) {
        p.clear();
        long long suma=0,sumb=0;
        for(int i=0;i<n;i++) {
            long long a,b;
            scanf("%lld%lld",&a,&b);
            suma+=a,sumb+=b;
            p.push_back(a-b);
        }
        sort(p.begin(),p.end());
        if(sumb>m)
            puts("-1");
        else {
            bool flag=false;
            int cnt=0;
            for(int i=n-1;i>=0;i--) {
                if(suma<=m) {
                    flag=true;
                    printf("%d\n",cnt);
                    break;
                }
                cnt++;
                suma-=p[i];
            }
            if(!flag) {
                if(suma<=m)
                    printf("%d\n",cnt);
                else
                    puts("-1");
            }
        }
    }
    return 0;
}
发布了45 篇原创文章 · 获赞 1 · 访问量 6764

猜你喜欢

转载自blog.csdn.net/Ls_attack/article/details/104066091
今日推荐