湖南大学 十四届ACM程序设计新生杯 题解

A-AFei Loves Magic

思路:如果两个魔法石相遇,需要改变各自的方向并且以和原来相同的速度前进。这是和魔法石在同一地方相遇,但是方向不变,继续运动是等价的。因此只需算出t时间后还有多少,魔法石在(0,L)中即可。

代码

#include <iostream>
 
using namespace std;
const int N = 1e6 + 10;
int x, d;
int n, L, t;
 
int main()
{
    cin >> n >> L >> t;
    int res = 0;
    for (int i = 0; i < n; i ++)
    {
        cin >> x >> d;
        if (d == 1 && x >= L - t)    res ++;
        if (d == 2 && x - t <= 0)    res ++;
    }
    cout << n + 1 - res;
}


B - bearBaby loves sleeping
裸BFS,算出两点间最短距离

#include <iostream>
#include <cstring>
using namespace std;

typedef pair<int, int> PII;
#define x first
#define y second
const int N = 110;
int w[N][N];
int dist[N][N];
PII q[N * N];
int n, m, ex, ey;
int dx[4] = {-1 ,0, 1, 0};
int dy[4] = {0, 1, 0, -1};

int main()
{
    cin >> n >> m;
    cin >> ex >> ey;
    
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            cin >> w[i][j];
    
    int hh = 0, tt = 0;
    q[0] = {1, 1}, dist[1][1] = 0;
    
    while (hh <= tt)
    {
        auto t = q[hh ++];
        int tx = t.x, ty = t.y;
        if (tx == ex && ty == ey)
        {
            cout << dist[tx][ty];
            return 0;
        }
        
        for (int i = 0; i < 4; i ++)
            for (int j = 0; j < 4; j ++)
            {
                int sx = tx + dx[i];
                int sy = ty + dy[i];
                if (sx <= 0 || sx > n || sy <= 0 || sy > m || w[sx][sy] || dist[sx][sy])    continue;
                dist[sx][sy] = dist[tx][ty] + 1;
                q[++ tt] = {sx, sy};
            }
    }
}



C-Sleepy Kaguya
通过前几项可以猜测:如果n是负数,则输出-1,否则是1。
如果需要证明,可以通过数学归纳法。

代码

#include <iostream>

using namespace std;

int main()
{
    long long n;
    cin >> n;
    if (n & 1)    cout << -1;
    else cout <<  1;
}


D-Dandan’s lunch
根据作出的题目量,得到相应数量的蛋糕数。难点是怎么求出蛋糕数(即三角形的面积)
我运用了海伦公式
在这里插入图片描述
公式描述:公式中a,b,c分别为三角形三边长,p为半周长,S为三角形的面积。

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

typedef pair<int ,int> PII;
const int N = 1e5 + 10;
PII person[N];
double tri[N];

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++)
    {
        int num;
        double x1, y1, x2, y2, x3, y3;
        
        cin >> num >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        person[i] = {num, i};
        
        double a = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
        double b = sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1));
        double c = sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));
        
        double p = (a + b + c) / 2;
        double s = 2 * sqrt(p * (p - a) * (p - b) * (p - c));
        tri[i] = s;
    }
    sort(tri, tri + n);
    sort(person, person + n);
    
    for (int i = 0; i < n; i ++)
    {
        if (person[i].second == 0)
            cout << (long long)(tri[i] + 0.5);
    }
}




E-Easy problem
找出x的倍数,要求找出的倍数包含所有题目要求的数字。
一开始我理解错了,以为找出的倍数只能是要求的数字且所有数字都要使用,所以卡了很久。
注意 1<=x<=1e8, y <= 1e18
可以设y = 123456789000000000。
①如果y是x的倍数,直接输出。
②如果不是,调整y的值,y % x是多出来的值,因此在y的基础上再加上x - y % x,y即是x的倍数。又因为x是1e8范围内的数,所以y改变只改变低位的值,变为1234567890XXXXXXXX。

代码

#include <iostream>

using namespace std;

int main()
{
    int t;
    cin >> t;
    while (t --)
    {
        long long n = 123456789000000000;
        int x, k;
        cin >> x >> k;
        while (k --)
        {
            int mm;
            cin >> mm;
        }
        
        if (x % n)    cout << n + (x - n % x) << endl;
        else
            cout << n;
    }
    
}


F-Find the AFei Numbers
数位DP
似乎做麻烦了,等看了题解再改
(似乎可以f[i][j], j记录两位数]

#include <iostream>
#include <vector>

using namespace std;
const int N = 20;
long long f[N][10];
long long tens[N];

void init()
{
    tens[0] = 1;
    for (int i = 1; i < N; i ++)
        tens[i] = tens[i - 1] * 10;
    
    for (int i = 1; i < N; i ++)
        for (int j = 0; j <= 9; j ++)
        {
            if (j == 5)
            {
                if (i - 3 >= 0)
                {
                    f[i][j] += tens[i - 3];
                    for (int k = 1; k <= 9; k ++)
                        f[i][j] += f[i - 2][k];
                    for (int k = 0; k <= 9; k ++)
                        if (k != 2)
                            f[i][j] += f[i - 1][k];
                }
            }
            else
            for (int k = 0; k <= 9; k ++)
                f[i][j] += f[i - 1][k];
        }
}

int main()
{
    init();
    int t;
    cin >> t;
    
    while (t --)
    {
        long long n;
        cin >> n;
        long long res = 0;
        
        vector<int> nums;
        while (n)
        {
            nums.push_back(n % 10);
            n /= 10;
        }
        
        int last0 = -1;
        int last1 = -1;
        int last2 = -1;
        
        for (int i = nums.size() - 1; i >= 0; i --)
        {
            int flag = 0;
            int x = nums[i];
            for (int j = 0; j < x; j ++)
            {
                if (last2 == 5 && j == 2)
                {
                    if (i > 0)
                        res += tens[i - 1];
                    for (int k = 1; k <= 9; k ++)
                        res += f[i][k];
                }
                else if (last1 == 5 && last2 == 2 && j == 0)
                {
                    res += tens[i];
                }
                else
                    res += f[i + 1][j];
            }
            last0 = last1;
            last1 = last2;
            last2 = x;
            if (last0 == 5 && last1 == 2 && last2 == 0)
            {
                long long num = 0;
                for (int k = i - 1; k >= 0; k --)
                {
                    num *= 10;
                    num += nums[k];
                }
                num ++;
                res += num;
                flag = 1;
                break;
            }
            
            if (flag)
                break;
        }
        cout << res << endl;
    }
}

H - Kuangyeye and hamburgers
排序后求前缀和即可
s[n] = w[1]+w[2] … + w[n]
w[a]+w[a + 1]…+w[b] = s[b] - s[a - 1]

#include <iostream>
#include <algorithm>

using namespace std;
const int N = 1e5 + 10;
int w[N], s[N];
int n, k;

typedef long long LL;

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i ++)
    {
        cin >> w[i];
    }
    
    sort(w + 1, w + n + 1, greater<int>());
    for (int i = 1; i <= n; i ++)
    {
        s[i] = s[i - 1] + w[i];
    }
    
    LL res = -1;
    for (int i = 0; i < k; i ++)
    {
        int a, b;
        cin >> a >> b;
        res = max(res, (LL)s[b] - s[a - 1]);
    }
    cout << res;
}


I - II play with GG
博弈论
需要用到SG函数的知识
SG[x][y] = mex(SG[x -1][y], SG[x][y], SG[x][y-1])

最后算出起点的SG值,如果是0,则gg赢,否则II赢

#include <iostream>
#include <unordered_set>
#include <cstring>

using namespace std;
const int N = 1010;
int sg[N][N];
int x, y;
int dx[3] = {-1, -1, 0};
int dy[3] = {0, -1, -1};

int dfs(int x, int y)
{
    unordered_set<int> st;
    if (sg[x][y] != -1)    return sg[x][y];
    for (int i = 0; i < 3; i ++)
        {
            int ex = x + dx[i];
            int ey = y + dy[i];
            if (ex < 0 || ey < 0)    continue;
            st.insert(dfs(ex, ey));
        }
    for (int i = 0; ;i ++)
        if (!st.count(i))
           return sg[x][y] = i;
}

int main()
{
    memset(sg, -1, sizeof sg);
    
    cin >> x >> y;
    
    dfs(x, y);
    
    if (sg[x][y] == 0)
        cout << "gg";
    else
        cout << "ii";
}


J - Less taolu
用数组记录状态避免重复搜索

#include<iostream>
using namespace std;
const long long mod = 1e9+7;
int f[100010];

long long func(int x){
    if (f[x])
        return f[x];
    if (x==1||x==0){
        return 1;
    }
    return f[x] = (x*func(x-1)+(x-1)*func(x-2))%mod;
}
int n;
int main(){
    cin>>n;
    cout<<func(n);
    return 0;
}



L - The Right-angled Triangles
双指针
考虑若为直角三角形
则c^2 = a ^ 2 + b ^ 2
若直接枚举,显然会TLE。
所以先将[1,45000]的平方和存入数组中,对于输入的c,
设置双指针找到是否存在满足条件a ^ 2 + b ^ 2 = c ^ 2的值。时间复杂度为O(TC)

#include <iostream>
#include <cstring>

using namespace std;
const int N = 4e5 + 10;
int w[N];

int main()
{
    for (int i = 1; i <= 45000; i ++)
        w[i] = i * i;
    
    int t, c;
    cin >> t;
    while (t --)
    {
        cin >> c;
        c = c * c;
        int l = 1, r = 45000;
        bool flag = 0;
        while (l <= r)
        {
            while (w[l] + w[r] < c)
                l ++;
            while (w[l] + w[r] > c)
                r --;
            if (w[l] + w[r] == c)
            {
                flag = 1;
                break;
            }
        }
        if (flag)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
}


L - The Digits String
矩阵快速幂+DP
设f[i][j]表示长度为i,i个数字的和模4为j的方案数

则f[i][0]可由f[i -1][0]序列后添0,4,8得。由f[i -1][1]序列后添3,7得。
由f[i -1][2]序列后添2,6得。由f[i -1][3]序列后添1,5,9得。

对其余三个状态同理

可得到状态转移方程
(f[i][0],f[i][1],f[i][2],f[i][3]) = (f[i - 1][0],f[i - 1][1],f[i - 1][2],f[i - 1][3]) * A
A为4 * 4矩阵
在这里插入图片描述

#include <iostream>
#include <cstring>

using namespace std;
const int mod = 2019;

void mul(int c[][4],int a[][4], int b[][4])
{
    static int temp[4][4] = {0};
    memset(temp, 0, sizeof temp);
    
    for (int i = 0; i < 4; i ++)
        for (int j = 0; j < 4; j ++)
           for (int k = 0; k < 4; k ++)
               temp[i][j] = (a[i][k] * b[k][j] + temp[i][j]) % mod;
    memcpy(c, temp, sizeof temp);
}

int main()
{
    int n;
    while (cin >> n)
    {
        int f1[4][4] = {3, 3, 2, 2};
        int a[4][4] = {
        {3, 3, 2, 2},
        {2, 3, 3, 2},
        {2, 2, 3, 3},
        {3, 2, 2, 3}
        };
        n --;
        while (n)
        {
            if (n & 1)    mul(f1, f1, a);
            mul(a, a, a);
            n = n >> 1;
        }
        
        cout << f1[0][0] << endl;
    }
}

13届
L - Liao Han
题目描述:题目的意思是给定一个正整数n,求1-n中,约数个数为奇数的数的个数。

唯一分解定理,任意正整数n可分解为
在这里插入图片描述
其中p为质数。
从而可以得到N的约数个数为在这里插入图片描述
一个数的约数个数为奇数,才是符合题目要求的,可以某个数满足题目要求和该数字是完全平方数是等价的。
①如果该数满足要求,则其所有a必然是偶数,因此是一个完全平方数。
②如果该数是一个完全平方数,则经过分解后,其指数(即a)必然是2的倍数,约数个数是奇数。

因此只要算出1-n中有几个完全平方数,即sqrt(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值