SWPU-ACM集训队周赛之个人赛(3-18)----题解

时间:2021-12-08 13:50:27

今天的比赛题目不是特别简单,但是也有3题是水题系列,另外的三题学的比较努力的同学一定都见过原题,没有3题的同学自己面壁去,比赛连接在这里点击打开链接


A:按照题目的题意去找这样的约数就行了,可以循环去找,也可以拿一个vector之类的东西去存,每一份数据花的时间是C*C*B+A,还要乘上一个数据的份数,所以最坏的情况会爆int,所以拿long long 去存

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
 
int main(){
    ll n,m,k;
    vector<ll>v;
    while(cin>>n>>m>>k){
        v.clear();
        for(ll i = 1;i*i <= k;i++){
            if(k%i == 0) v.push_back(i);
            if(k%i == 0&&i*i!=k) v.push_back(k/i);
        }
        sort(v.begin(),v.end());
        int minn = (v[0]*v[0]*m+n)*(k/v[0]),mi = 0;
        for(ll i = 0;i < v.size();i++){
            ll x = (v[i]*v[i]*m+n)*(k/v[i]);
            if(minn > x) minn = x,mi = i;
        }
        printf("%lld\n",v[mi]);
    }
    return 0;
}


B:在草稿本上可以写一写,发现每个最终陷入死循环的数在某一次执行函数的时候会出现89这个东西(当然也可以是其他的数字,总之是一个会陷入死循环的数就行了),其实会出现的很快,就最多循环15次左右就会出现,具体做法见代码:


#include <bits/stdc++.h>

using namespace std;

int fun(int n){
    int sum = 0;
    while(n>0){
        sum += (n%10)*(n%10);
        n /= 10;
    }
    return sum;
}

int main(){
    int n;
    while(cin>>n){
        while(1){
            if(fun(n) == 1) {puts("YES");break;}
            else if(fun(n) == 89) {puts("NO");break;}
            n = fun(n);
        }
    }
    return 0;
}


C:这套题里面比较难的两个题之一,但是出现在寒假训练的kuangbin带你飞专题里,题目说了要去找最少的步数,那么很容易想到用bfs来做这道题目,需要注意的是当n>k时,只能一直往后一步一步走,直接输出n-k即可

#include <bits/stdc++.h>

using namespace std;

bool vis[100005];
int step[100005];
queue <int>q;

int bfs(int n,int k){
    int head,next;
    q.push(n);
    vis[n] = true;
    while(!q.empty()){
        head = q.front();
        q.pop();
        for(int i = 0;i < 3;i++){
            if(i == 0) next = head+1;
            else if(i == 1) next = head-1;
            else next = head*2;
            if(next < 0||next > 100000) continue;
            if(!vis[next]){
                q.push(next);
                step[next] = step[head]+1;
                vis[next] = true;
            }
            if(next == k) return step[next];
        }
    }
    return -1;
}

int main(){
    int n,k;
    while(cin>>n>>k){
        memset(vis,false,sizeof(vis));
        memset(step,0,sizeof(step));
        while(!q.empty()) q.pop();
        if(n >= k) cout<<n-k<<endl;
        else cout<<bfs(n,k)<<endl;
    }
    return 0;
}


D:大家是不是觉得这道题似曾相似呢?对,没有错,这道题就是新生赛决赛的那道dp题,也是我的原创题,之前大一大二的同学没有人做出来,今天把这道题又重新拿出来给大家写 ,不知道还有多少人有印象。一道很基础的动态规划,只是需要注意的是有负数,初始化dp的时候需要赋值一个1e6左右的负数,然后写出状态转移方程dp[i][j] =max(dp[i][j-1],dp[i-1][j],max(dp[i][k1],dp[i][k2],...,dp[i][kn])j%ki == 0) 就可以了

#include <bits/stdc++.h>

using namespace std;

int main(){
    int t,n,m;
    int num[35][105];
    int dp[35][105];
    while(~scanf("%d%d",&n,&m)){
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= m;j++)
                scanf("%d",&num[i][j]);
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= m;j++)
                if(num[i][j] < 0) num[i][j]*=2;
        for(int i = 0;i <= n;i++)
            for(int j = 0;j <= m;j++)
                dp[i][j] = -10000000;
        dp[1][1] = num[1][1];
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= m;j++){
                for(int k = 1;k < j;k++){
                    if(j%k == 0){
                        dp[i][j] = max(dp[i][j],dp[i][k]+num[i][j]);
                    }
                }
                dp[i][j] = max(max(dp[i][j],dp[i][j-1]+num[i][j]),dp[i-1][j]+num[i][j]);
            }
        }
        printf("%d\n",dp[n][m]);
    }
    return 0;
}


E:又是一道原题,就是上一次博弈论算法讲堂讲的一道尼姆博弈的例题吗,甚至都没有涉及sg函数,这都做不出来,可以去面壁了

#include <bits/stdc++.h>

using namespace std;

int main(){
    int n,a[105],ans,cot;
    while(cin>>n){
        ans = 0;
        cot = 0;
        memset(a,0,sizeof(a));
        for(int i = 0;i < n;i++){
            cin>>a[i];
            ans^=a[i];
        }
        if(ans == 0) puts("0");
        else{
            for(int i = 0;i < n;i++){
                int k = ans^a[i];
                if(k < a[i]) cot++;
            }
            cout<<cot<<endl;
        }
    }
    return 0;
}


F:其实这道题才是全场最水的题目,只要理解了题意就可以很快的AC掉它啦,注意一下时间最多看90分钟,循环一遍去找连续的无聊时间就可以了

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e5+7;
int v[100];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(v,0,sizeof(v));
        for(int i=1; i<=n; i++)
        {
            int x;
            scanf("%d",&x);
            v[x]=1;
        }
        int now=0,sum=0;
        for(int i=1; i<=90; i++)
        {
            sum++;
            if(v[i])now=0;
            else now++;
            if(now==15)
            {
                break;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}