ShanDong Multi-University Training #6题解

题目解析(暂时还有CDFI没补)

A - The vowel is the best letters

B - The treasure you find is the best treasure

C - The biggest number is the best number

D - The longest string is the best string

E - The most regular graphics is the best graphic

F - The most suitable structure is the best structure

G - The smallest move is the best move

H - The smartest candidates is the best candidate

I - The most capable man is the best man

J - The highest mountain is the best mountain

K - The fullest bag is the best bag

L - The question from Carl are the best questions


A - The vowel is the best letters(构造+规律)

题目大意:给定一个只包含小写阿拉伯字母的字符串,问通过构造可以构造出几种方式。

构造方式:

一、对于元音‘a','e','i','o','u',将其加入到最后一位,并将整个字符串反转

二、对于其他字母,加入到最后一位

思考方式以及情况判断:

思考方式:按有1 2 3位元音模拟

情况判断:

1.当没有元音时只有一种方式

2.当有元音且只有一个时,该元音必然在开头,样例如ca是不合理的,会反转变成ac

3.当元音超过一个时,必须要有一个元音在开头。

根据样例acmicpc得出三种情况分别为

imcacpc

micacpc

cmiacpc

扩展到三位可知道如acmicec

icemcac

ciemcac

多位以后也会根据此变换方式改变变换方式,使得中间偏后的两位换到最前面,而前面可以在此之间自由变换位置。见acmicpc中i的位置。

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

string str;
bool check(char s)
{
    if(s == 'a' || s == 'e'|| s == 'i' || s == 'o' || s == 'u') return true;
    return false;
}
void solve()
{
    vector<int>v;
    cin >> str;
    for(int i = 0; i < str.size(); i ++)
        if(check(str[i])) 
            v.push_back(i);
    int cnt = v.size();
    //cout << v.size() << endl;
    bool st = check(str[0]);
    if(!cnt)
    {
        puts("1");
        return;
    }
    if(cnt && !st)
    {
        puts("0");
        return;
    }
    if(cnt == 1 && st)
    {
        cout << str.size() << '\n';
        return;
    }
    if(cnt > 1 && st)
    {
        if(cnt & 1) cout << v[cnt / 2 + 1] - v[cnt / 2] << '\n'; 
        else cout << v[cnt / 2] - v[cnt / 2 - 1] << '\n'; 
    }
}
int main()
{
    
    solve();



    system("pause");
    return 0;
}

B - The treasure you find is the best treasure(长得像数位dp的dfs)

真nm简单!

注意要点:边走边取模解决大数整除问题,同位剪枝

题目大意:给定有位置上数字未知的高精度整数,找到满足整除并且没有前导0的的最小数

暴力遍历每一位情况即可

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1010;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
string str;
int n;
bool st = false;
int ans[N];
bool b[N][N];
void dfs(int pos,int div)
{
    if(pos == str.size())
    {
        if(!div)    st = true;  
        return;
    }
       
    if(str[pos] >= '0' && str[pos] <= '9')
    {
        ans[pos] = str[pos] - '0';
        b[pos][(div * 10 + ans[pos]) % n] = true;
        dfs(pos + 1,(div * 10 + ans[pos]) % n);
    }
    else 
    {
        for(int i = 0; i <= 9; i ++)
        {
            if(pos == 0 && i == 0) continue;
            if(!b[pos][(div * 10 + i) % n])
            {
                ans[pos] = i;
                b[pos][(div * 10 + i) % n] = true;
                dfs(pos + 1,(div * 10 + i) % n);
            }
            if(st) break;
        }
    }
    return;
}
void solve()
{
    cin >> str;
    cin >> n;
    dfs(0,0);
    if(st)  
    {
        for(int i = 0;i < str.size();  i ++) 
            putchar('0' + ans[i]);
        puts("");
    }
    else puts("*");
    return;
}
int main()
{
    solve();



    system("pause");
    return 0;
}

C - The biggest number is the best number(lca)

D - The longest string is the best string(trie+ac自动机)

E - The most regular graphics is the best graphic(几何)

题目大意:.是白的#是黑的求至少(长度大于1的算一条)有多少条边

思路:点在四个的块中为3或1算一条边

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 110;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

char s[N][N];

bool check(int x,int y)
{
    //if(st[x][y]) return false;
    int sum = (s[x][y] == '.') + (s[x - 1][y - 1] == '.') + (s[x - 1][y] == '.') + (s[x][y - 1] == '.');
    if(sum == 3 || sum == 1) return true;
    else return false;
}void solve()
{
    int ans = 0;
    int n,m;
    cin >> n >> m;
    for(int i = 0; i < n; i ++) cin >> s[i];
    for(int i = 1; i < n; i ++)
    {
        for(int j = 1; j < m;j ++)
        {
            if(check(i,j)) ans ++;
        }
    }
    cout << ans << '\n';


}
int main()
{
    solve();



    system("pause");
    return 0;
}

F - The most suitable structure is the best structure(势能线段树)

G - The smallest move is the best move(思维)

https://zhuanlan.zhihu.com/p/268630329

题目大意:给定n个有序对<ai,bi>,作为机器人的位置m个有序对<ai,bi>作为灯的位置,考虑通过对所有盗贼向右移动(A)或向上移动(B),使得所有盗贼能出去的的最小值

题目思路:对于在灯内的盗贼,可以直上或直下或者拐弯,可以通过遍历一个方向,从而找出令一个方向满足恰好出去(最大值)的最小值。

题目解法:存出在灯内,走过ci - ai 的并能出去的最大值y,那么对于任何一个>=x都成立,寻找最小值

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

int a[N],b[N],c[N],d[N];
int cnt[N];
void solve()
{
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
    for(int j = 1; j <= m; j ++) cin >> c[j] >> d[j];

    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
        {
            if(a[i] <= c[j] && b[i] <= d[j])
            {
                cnt[c[j] - a[i]] = max(cnt[c[j] - a[i]],d[j] - b[i] + 1);
            }
        }
    int maxn = 0;
    int ans = INF;
    for(int i = N; i >= 0; i --)
    {
        maxn = max(maxn,cnt[i]);//向上最多
        //cout << maxn << endl;
        ans = min(ans,i + maxn);
    }   
    cout << ans << endl;


}
int main()
{
    solve();



    system("pause");
    return 0;
}

H - The smartest candidates is the best candidate(思维+贪心)

题目大意:祖安竞选,如果范德尔去一个城市宣讲,那么原来支持希尔科和范德尔的都支持范德尔,如果不去,原本支持范德尔的那些人就会放弃选举,原本支持希尔科的人会继续支持希尔科。问至少参加几次竞选可以让范德尔稳赢

假设原本支持范德尔的总和是sumb,原本支持希尔科的总和是suma,支持范德尔的是bi,希尔科的是ai;

对于去的城市,范德尔:sumb + a  希尔科:suma - a

对于不去的城市:范德尔:sumb - b  希尔科:suma

因此对于范德尔去和不去的总考虑值就是sumb + a - (sumb - b) =  a + b

因此对于希尔科去和不去的总考虑值就是suma - a - suma =  -a

根据峡谷相对论,我吃对面一组F6,相当于我赢一组F6,对面输一组F6,我赢两波!

因此对面输a实际上我得利2a,总考虑值2a+b,贪心排序即可

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

struct node
{
    ll x,y;
    bool operator < (const node w) const 
    {
        return 2 * w.x + w.y < 2 * x + y;
    }
}a[N];
void solve()
{
    int n;
    scanf("%d",&n);
    ll suma = 0,sumb = 0;
    for(int i = 0; i < n; i ++)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        a[i] = {x,y};
        suma += x;
    }
    sort(a,a + n);
    // for(int i = 0; i < n; i ++)
    // {
    //     cout << a[i].x << " " << a[i].y << endl;
    // }
    for(int i = 0; i < n; i ++)
    {
        sumb += a[i].x + a[i].y;
        suma -= a[i].x;
        if(sumb > suma) 
        {
            cout << i + 1 << '\n';
            return;
        }
    }

}
int main()
{
    solve();



    system("pause");
    return 0;
}

I - The most capable man is the best man(思维)

J - The highest mountain is the best mountain(思维签到)

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 310;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

int a[N][N];
int d[6];
void solve()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            scanf("%d",&a[i][j]);
    int ans = -1;
    for(int i = 2; i <= n; i ++)//遍历边长有几个点的正方形,边长为i - 1
    {
        for(int len = 1; len + i - 1 <= n; len ++)//遍历左上角的点的横坐标
        {
            for(int j = 1; j + i - 1 <= n;j ++)//遍历左上角的纵坐标
            {
                
                d[0] = a[len][j];//左上
                d[1] = a[len + i - 1][j];//左下
                d[2] = a[len][j + i - 1];//右上
                d[3] = a[len + i - 1][j + i - 1];//右下
                sort(d,d + 4);
                if(d[0] == d[2] && d[3] > d[2]) ans = max(ans,d[0]);
            }
        }
    }
   printf("%d\n",ans);

}
int main()
{
    
    solve();



    system("pause");
    return 0;
}

K - The fullest bag is the best bag(思维+优先队列实现)

题目大意:n体积的背包,m个物品,物品的体积都是2的倍数,并且每个物品可以等分成两份。问填满背包的最大分次数,如果填不满就是-1

思考方式以及情况判断:

思考方式:题目1 <= n <= 1e18 过大没法直接使用背包dp(如果有我太菜惹不知道QAQ)

考虑贪心。

情况判断:

只有当总和加起来也填不满才会出现-1,其他时候都会有解。

贪心的去把他从大到小的放。粗略证明:如果先放小的,对于大的不能放需要砍大的,不能用小的凑,

例子:

33 4

1 2 4 32

显然答案是0,然而如果我从小往大放的话,需要砍32,必然不是最优解,从而考虑:

(1)用优先队列贪心 --- 每次切两半的数保证次序

(2)从大到小放:

  1、如果能放,则把他放进去

  2、如果不能放,并且还装不满,把他砍成两半

  3、如果不能放进去,还能装满,直接扔掉就好惹

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;


void solve()
{
    ll n,m,sum = 0;
    cin >> n >> m;
    priority_queue<int>heap;
    for(int i = 0; i < m; i ++)
    {
        int x;
        cin >> x;
        heap.push(x);
        sum += x;
    }
    if(sum < n) 
    {
        puts("-1");
        return;
    }
    //这里的sum实际上是总的集合
    ll ans = 0;
    while(n)
    {
        auto t = heap.top();
        heap.pop();
        if(n >= t)//能放进去
        {
            n -= t;
            sum -= t;
        }
        else if(n > sum - t)//放不进去了,并且如果不放他就放不满
        {
            heap.push(t >> 1);
            heap.push(t >> 1);
            ans ++;
        }
        else
            sum -= t; //处理集合给他扔掉
    }
    cout << ans << endl;

}
int main()
{
    int t;
    cin >> t;
    while(t --)
    solve();



    system("pause");
    return 0;
}

PS:下边是从小到大的方式,不做过多解释(xyggyyds)

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

void solve()
{
    ll n, m;
    cin >> n >> m;
    vector<int> f(62);
    ll sum = 0;
    for (int i = 1; i <= m; i++)
    {
        int x;
        cin >> x;
        sum += x;
        for (int j = 0; j <= 31; j++)
        {
            if ((1ll << j) & x)  f[j]++;
        }
    }
    //cout << sum << endl;
    if (sum < n)
    {
        puts("-1");
        return;
    }
    int ans = 0;
    for (int i = 0; i <= 60; i++)
    {
        if ((1ll << i) & n)
        {
            if (f[i])   f[i]--;
            else
            {
                int j = i + 1;
                for (j; j <= 60; j++)
                    if (f[j])   break;
                for (j; j > i; j--)
                    f[j]--, f[j - 1] += 2, ans++;
                f[i]--;
            }
        }
        f[i + 1] += f[i] / 2;
    }
    cout << ans << endl;
}
int main()
{
    int t;
    cin >> t;
    while(t --)
    solve();

    system("pause");
    return 0;
}

L - The question from Carl are the best questions(思维签到)

题目大意:

gcd(a,b) == gcd(c,d)

min(c,d) > max(a,b)

给定1<= a,b<= 1e9 求1<=c,d<=1e15

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;


void solve()
{
    ll a,b;
    scanf("%lld%lld",&a,&b);
    int t = __gcd(a,b);//找到最大公因数
    int maxn = max(a,b);//找到最大数
    int qwq = maxn / t;//找到和最大公因数差多少倍
    printf("%lld %lld\n",(qwq + 1) * t,(qwq + 2) * t);

}
int main()
{
    int t;
    cin >> t;
    while(t --)
    solve();



    system("pause");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值