SDUT 2023 summer team contest(for 22) - 7

A - JB Loves Math

题意:给你两个数a,b,让你找一个奇数x,一个偶数y,a只能加x或减y,问让你最少操作几次可以令a==b

思路:我们将其分为三大种情况

1:a==b,ans==0

2:   a>b,这时如果a与b的差值为偶数ans==1,否则为奇数的时候我们一定可以通过减去一个偶数再加上一个奇数,令a==b,例如a==10,b==3,让a-8=2,2+1=3,

3:a

①:其差值为偶数,差值除以2后为奇数,我们可以通过加二次奇数令a==b,a=4,b=10

a+3+3=10=b(ans==2)

② :其差值为偶数,差值除以2后还为偶数,那么我们只能加两次奇数再减去一个偶数即可

例如a=2,b=10,想让a比b多偶数,a+5+5=12,12-b=2为偶数,12-2=10=b(ans==3)

#include 
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int a, b;
void solve()
{

    cin >> a >> b;
    if (a == b)
        cout << 0 << endl;
    else if (a > b)
    {
        int x = a - b;
        if (x % 2 == 0)
            cout << 1 << endl;
        else
            cout << 2 << endl;
    }
    else
    {
        int x = b - a;
        if (x % 2 == 1)
            cout << 1 << endl;
        else
        {
           if( x / 2 % 2 == 1) cout << 2 << endl;
            else cout << 3 << endl;
        }
    }
}
signed main()
{
    Ysanqian;
    int T;
    // T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

B-JB Loves Comma

C - JB Wants to Earn Big Money

这两个没什么说的直接写就可以了

G - Easy Glidet

 题意:二维平面,给你起始点,终点的坐标,还有一些加速点,经过加速点的后三秒可以加速,

问你最小花费时间

思路:看题面说的最多1000个加速点,我们暴力建边,跑dijkstra即可

建边过程记得什么时候可以加速即可

#include 
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int s, t, n;
int x[N], y[N];
int v1, v2;
struct egde
{
    int v;
    double w;
};
vector g[N];
bool st[N];
double dist[N];
double dis(int x1, int y1, int x2, int y2) // 计算坐标距离
{
    return 1.0 * sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
double tt(double dis, int flag) // 计算时间,我们以时间为边权
{
    if (flag) // flag为1,为加速的情况
    {
        if (1.0 * dis / v2 <= 1.0 * 3)
            return 1.0 * dis / v2;
        else
            return (dis - 3 * v2) / v1 + 3;
    }
    else // 正常速度的情况
        return 1.0 * dis / v1;
}
void dijkstra() // 堆优化的版子
{
    dist[0] = 0;
    priority_queue, greater> q;
    q.push({dist[0], 0});
    while (q.size())
    {
        int u = q.top().yy;
        q.pop();
        if (st[u])
            continue;
        st[u] = 1;
        for (auto ed : g[u])
        {
            int v = ed.v;
            double w = ed.w;
            if (dist[v] > dist[u] + w)
            {
                dist[v] = dist[u] + w;
                q.push({dist[v], v});
            }
        }
    }
}
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> x[i] >> y[i]; // 记录坐标点
    cin >> x[0] >> y[0] >> x[n + 1] >> y[n + 1];
    cin >> v1 >> v2;             // 读入数度
    for (int i = 1; i <= n; i++) // 先暴力建所有加速点的边
    {
        for (int j = i + 1; j <= n; j++)
        {
            double time = 1.0 * tt(dis(x[i], y[i], x[j], y[j]), 1);
            g[i].pb({j, time});
            g[j].pb({i, time});
        }
    }
    for (int i = 1; i <= n; i++)
    {
        double time1 = 1.0 * tt(dis(x[0], y[0], x[i], y[i]), 0); // 建加速点和起点的边,注意这里不能加速
        g[0].pb({i, time1});
        g[i].pb({0, time1});
        double time2 = 1.0 * tt(dis(x[n + 1], y[n + 1], x[i], y[i]), 1); // 建加速点和终点的边,注意这里可以加速
        g[n + 1].pb({i, time2});
        g[i].pb({n + 1, time2});
    }
    double time = 1.0 * tt(dis(x[0], y[0], x[n + 1], y[n + 1]), 0); // 建立起点终点的边
    g[0].pb({n + 1, time});
    g[n + 1].pb({0, time});
    memset(dist, 127, sizeof dist);
    dijkstra();
    printf("%.12lf", dist[n + 1]);
}
signed main()
{
    Ysanqian;
    int T;
    T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

I - Barbecue

题意给定一个长度为 n 的字符串,有多次询问,每次询问给一个区间,也就是一个子串,A 和 B 在博弈,每次操作可以从子串头或尾取删一个字符,删前或删后如果是回文,那么另一个人赢,A 先手,询问的是这个子串的赢家

思路:我们先想一下什么必胜态,或者必败态,我们想什么情况下A必输,无非就是A不论去头或者尾巴都为回文的情况,例如 ab,  abab,ababab, 我们发现这种状态下字符串长度只能为偶数,那么我去就想,如果一开始给的不是回文串,那么有两种情况,①只有长度变为1时为回文,②或者中间存在回文,对于第一种情况例如abcde,我们发现如果其长度为偶数那么A一定输,反之则盛,第二种情况,例如aaaababab,其变为回文的长度一定为偶数则还是故如果总其长度为偶数A输,反之赢,我们已经思路上解决了大半,剩下的就是如果一开始给的就是回文的(其长度一定为奇数)我们如何快速的不超时的判断呢,我们用字符串哈希,正哈希一遍,反哈希一遍,如果区间正反哈希值相等那就是回文串,

总之偶数的情况我们一定输,奇数的情况如果一开始不是回文的我们赢,反之输

#include 
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define ull unsigned long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353, P = 13331;
ull n, m;
string s;
ull hash1[N], hash2[N];
ull p[N];
ull gethash1(int l, int r)
{
    return (hash1[r] - hash1[l - 1] * p[r - l + 1]);
}
ull gethash2(int l, int r)
{
    return (hash2[l] - hash2[r + 1] * p[r - l + 1]);
}
void init()
{
    p[0] = 1;
    for (int i = 1; i <= N; i++)
        p[i] = p[i - 1] * P;
}
void solve()
{
    cin >> n >> m;
    cin >> s;
    s = " " + s;
    int len = s.size() - 1;
    hash1[0] = 0, hash2[len + 1] = 0;
    for (int i = 1; i < s.size(); i++)
    {
        hash1[i] = hash1[i - 1] * P + s[i] - 'a';
        hash2[len + 1 - i] = hash2[len + 2 - i] * P + s[len + 1 - i] - 'a';
    }
    for (int i = 0; i < m; i++)
    {
        int l, r;
        cin >> l >> r;
        if ((r - l + 1) % 2 == 0)
            cout << "Budada\n";
        else if (gethash1(l, r) == gethash2(l, r))
            cout << "Budada\n";
        else
            cout << "Putata\n";
    }
}
signed main()
{
    Ysanqian;
    int T;
    T = 1;
    init();
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

L - Candy Machine

题意:给你n个糖,你从其中选一个子集,令子集中的数大于其平均数最多

思路:这题的主要思路就是先将这个数组从小到大排序,然后依次比较每次去掉最大的一个数能取糖果的数量,最大的就是结果。因为如果每次去掉是最小的数的话,平均值会变大,取糖果的数量肯定会变小;如果每次去掉的是最大的数的话,平均值会变小,结果就会有变大的可能性。所以每次比较要去掉最大的数。

本题难点在于证明对所有前缀所对应的子集中一定会包含有正解子序列。

具体证明见学长的博客

那我们就后续做,前序做也可以

#include 
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int a[N];
int sum, ans, n;
double average;
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum += a[i];
    }
    average = 1.0 * sum / n;
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
    {
        if (1.0 * a[i] > average)
            ans++;
    }
    for (int i = n; i >= 2; i--)//由于我们是每次都去掉第i数,故最多去掉的还剩一个
    {
        sum -= a[i];
        average = 1.0 * sum / (i - 1);
        int x = upper_bound(a + 1, a + i, average) - a;
        ans = max(ans, i - x);
    }
    cout << ans << endl;
}
signed main()
{
    Ysanqian;
    int T;
    T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

M - BpbBppbpBB

题意:给定两种邮票来组成图形,我们把图形给你问你用了两种邮票各自多少种

思路:C型的黑格子数为146 ,洞为2个,S型的黑格子数为100,洞为一个

统计所有的黑格子数,和洞数,二元一次方程即可

x个C型,y个S型

146*x+100y=黑格子数,      2*x+y=白洞数

对于白洞我们跑一遍bfs,再加上边界判断就可以了

#include 
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int dx[13] = {0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1};
int dy[13] = {0, 1, -1, 0, 1, 2, -1, 0, 1, 2, 0, 1};
string s[N];
int n, m;
int num1, num2;
bool bfs(int x, int y)
{
    for (int i = 0; i < 12; i++)
    {
        int a = x + dx[i], b = y + dy[i];
        if (s[a][b] == '#')
            return false;
    }
    return true;
}
void solve()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> s[i];
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (s[i][j] == '#')
                num1++;
            else
            {
                if (bfs(i, j) 
                && s[i][j - 1] == '#' && s[i][j + 2] == '#' 
                && s[i + 1][j - 2] == '#' && s[i + 1][j + 3] == '#' 
                && s[i + 2][j - 2] == '#' && s[i + 2][j + 3] == '#' 
                && s[i + 3][j - 1] == '#' && s[i + 3][j + 2] == '#')
                    num2++;
            }
        }
    }

    cout << (100 * num2 - num1) / 54 << ' ' << num2 - (100 * num2 - num1) / 27;
}
signed main()
{
    Ysanqian;
    int T;
    T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

你可能感兴趣的:(训练赛,c++,算法,思维,数据结构)