Contest#1 题解

ADF是我写的…BCE是shr写的…
侵立删。

F

大水题…咕咕咕

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int a,b,c,d;
cin>>a>>b>>c>>d;
while(a>0&&c>0){
    c-=b;
    if(c>0)a-=d;
}
if(a>0)cout<<"Yes";
else cout<<"No";
return 0;
}

A

在这里插入图片描述
这个题有好几种方法
从题意来看,如果是快乐数,那么最后肯定为1,如果不是快乐数,说明最后不是一,会陷入一个死循环。
第一种做法:快慢指针。
如果快指针到达1,那么慢指针也一定到达1,如果快指针追上了慢指针,此时一定有环,说明陷入了死循环。
第二种:
用哈希判断有没有重复数字出现(unordered_map也可)
第三种:暴力500次或者1000次嘻嘻
快慢指针做法代码

#include <iostream>
using namespace std;

int CalNum(int n) {
    int ans = 0;
    while (n) ans += (n % 10) * (n % 10), n /= 10;
    return ans;
}

bool isHappy(int n) {
    int f = CalNum(n), s = n;
    while (f != s) {
        f = CalNum(f);
        f = CalNum(f);
        s = CalNum(s);
    }
    return f == 1;
}

int main() {
    int n;
    while (cin >> n) cout << (isHappy(n) ? "Yes" : "No") << endl;
    return 0;
}

哈希做法

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 5;
int book[100005];

int find(int x) {
    int t = (x % N + N) % N;
    while (~book[t] && book[t] != x) {
        t++;
        if (t == N)
            t = 0;
    }
    return t;
}

int CalNum(int &n) {
    int ans = 0;
    while (n) ans += (n % 10) * (n % 10), n /= 10;
    n = ans;
    return find(n);
}

bool isHappy(int n) {
    memset(book, -1, sizeof book);
    int k = find(n);
    while (!~book[k]) {
        book[k] = n;
        k = CalNum(n);
    }
    return n == 1;
}

int main() {
    int n;
    while (cin >> n) cout << (isHappy(n) ? "Yes" : "No") << endl;
}

暴力做法

#include<iostream>
using namespace std;
int Happy(int n){
    int ans = 0;
    while(n) ans += (n%10)*(n%10), n/= 10;
    return ans;
}
signed main(){
    int n; while(cin >> n){
        int T = 1000; while(T--) n = Happy(n);
        if(n==1) cout << "Yes" << endl;
        else cout << "No" << endl;
    }
}

B

在这里插入图片描述
在这里插入图片描述
简单分析一下问题,不难发现这是NIM问题的变式
而我们知道,对于引进的SG函数有

  1. 可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
  2. 可选步数为任意步,SG(x) = x;
  3. 可选步数为一系列不连续的数,用GetSG()计算
    之后分类讨论一下即可
#include <bits/stdc++.h>
using namespace std;
int n, ans;
int SG(int a,int b){
    if(a<b) return 0;
    int ans;
    if(a%b==0) ans=a/b;
    else{
        int m=a/b+1,x=(a/b)*b;
        int k=(a-x)/m;
        if(k>1) ans=SG(a-k*m,b);
        else ans=SG(a-m,b);
    }
    return ans;
}
int main() {
    int a, b;
    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        ans = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a >> b;
            ans ^= SG(a, b);
        }
        if (ans)
            cout << "L" << endl;
        else
            cout << "P" << endl;
    }
    return 0;
}

C

在这里插入图片描述
在这里插入图片描述
首先,我们知道回文串的顺序倒转后,与原串是一样的。
所以我们输入的字符串与倒转后的字符串求最长公共子序列,就可以获取其中的回文序列,剩下的在对应的位置补上相同的就可以构造出回文串

#include <bits/stdc++.h>
using namespace std;

const int N = 2e3 + 5;
int DP[N][N];

int LCS(string a, string b) {
    int AS(a.size()), BS(b.size());
    for (int i(1); i <= AS; i++)
        for (int j(1); j <= BS; j++)
            if (!i || !j)
                DP[i][j] = 0;
            else if (a[i - 1] == b[j - 1])
                DP[i][j] = DP[i - 1][j - 1] + 1;
            else
                DP[i][j] = max(DP[i - 1][j], DP[i][j - 1]);
    return DP[AS][BS];
}

void strings(string a, string &b) {
    for (auto it = a.rbegin(); it != a.rend(); it++) b += *it;
}

int main() {
    string a, b;
    cin >> a;
    strings(a, b);
cout << a.size() - LCS(a, b) << endl;
return 0;
}

D

在这里插入图片描述
在这里插入图片描述
首先,要找到最后方案中的H,设为maxH,枚举寻找方案的最小值
限制条件:躺着的人不能超过n/2,宽度尽可能小
枚举h从1到这些人中的最大高度:
1.如果一个人的wi和hi均大于maxh,则该方案不可行
2.如果某个人的h或w只有一项大于maxh,那么考虑他是否h和w互换
3.剩下的人按照wi-hi从大到小排序后贪心

借鉴博客网址:添加链接描述

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
using namespace std;
const int N=1010,maxs=1e9;
int n,w[N],h[N],mh,allw,ans=maxs;
bool cmp(const int &x,const int &y){
return w[x]-h[x]>w[y]-h[y];
}

int main(){
cin>>n;
for(int i=1;i<=n;i++){
    scanf("%d%d",&w[i],&h[i]);
    mh=max(w[i],max(mh,h[i]));
    allw+=w[i];
}
for(int maxh=1;maxh<=mh;maxh++){
    vector<int>v;
    int cnt=0,noww=allw;
    for(int i=1;i<=n;i++){
        if(w[i]>maxh&&h[i]>maxh){
            cnt=maxs;
            break;
        }
        else if (w[i]>maxh&&h[i]<=maxh)continue;
        else if(w[i]<=maxh&&h[i]>maxh){
            noww+=h[i]-w[i];
            cnt++;
        }
        else if(w[i]>h[i])v.push_back(i);
    }

    if(cnt>n/2)continue;
    sort(v.begin(),v.end(),cmp);
    for(int i=0;i<v.size()&&cnt+i<n/2;i++)noww+=h[v[i]]-w[v[i]];

    ans=min(ans,noww*maxh);
    }
    cout<<ans;
return 0;
}

E

在这里插入图片描述
在这里插入图片描述
考虑搜索的过程。一个显而易见的想法是用一个优先队列维护搜索的节点。每次
用代价最小的点开始进行扩展。但通过进一步观察,我们可以发现扩展的过程中
只会有两种代价,x 和 x + 1,因此这个优先队列可以用一个双端队列deque代
替。如果代价需要增加则放到队尾,否则放到队首。

#include <bits/stdc++.h>

#define x first
#define y second
#define PII pair<int, int>

using namespace std;

const int N = 310;

int dist[N][N];
bool st[N][N];
char g[N][N];
deque<PII> q;

int n, m;
int dx[] = { 0, 0, 1, -1 }, dy[] = { 1, -1, 0, 0 };

void bfs(int x, int y) {
    memset(dist, 0x3f, sizeof dist);
    dist[x][y] = 0;
    q.push_front({ x, y });
    while (q.size()) {
        PII t = q.front();
        q.pop_front();
        for (int i = 0; i < 4; i++) {
            int tx = dx[i] + t.x, ty = dy[i] + t.y;
            if (tx < 0 || tx >= n || ty >= m || ty < 0)
                continue;

            if (g[tx][ty] == '#' && dist[tx][ty] > dist[t.x][t.y] + 1) {
                dist[tx][ty] = dist[t.x][t.y] + 1;
                q.push_back({ tx, ty });
            } else if (g[tx][ty] == '.' && dist[tx][ty] > dist[t.x][t.y]) {
                dist[tx][ty] = dist[t.x][t.y];
                q.push_front({ tx, ty });
            }
        }
    }
}

int main() {
    cin >> n >> m;
    int x = 0, y = 0, sx = 0, sy = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            cin >> g[i][j];
            if (g[i][j] == 'S')
                x = i, y = j, g[i][j] = '.';
            if (g[i][j] == 'T')
                sx = i, sy = j, g[i][j] = '.';
        }

    bfs(x, y);

    cout << dist[sx][sy] << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值