Gym101341题解

Posted RDCのACM奇幻之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym101341题解相关的知识,希望对你有一定的参考价值。

难度分类

(div2A-B):B C D G H M

(div2C-D):E K

(  div2E  ):A J I

喵喵喵:F L

 

A.

 

B.

题意:给一个长度为2~2e5的串,交换两个字符,要求最后没有"happiness" 

坑点:本来没有"happiness",交换一把,出现了“happiness”,这下好!

 

code1:(比赛时的,一点也不典雅~)

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
char s[500000+10];
vector<int> v;
int main()
{
    scanf("%s", s+1);
    int n = strlen(s+1);
    for(int i=1;i+8<=n;i++)
    {
        if(s[i] == \'h\' && s[i+1] == \'a\' && s[i+2] == \'p\' && s[i+3] == \'p\' && s[i+4] == \'i\' && s[i+5] == \'n\'&& s[i+6] == \'e\' && s[i+7] == \'s\' && s[i+8] == \'s\') 
        {
            v.push_back(i);
        }
    }

    if(v.size() == 0)
    {
        printf("YES\\n");
        for(int i=2;i<=n;i++)
        {
            swap(s[1], s[i]);
            int gg = 0;
            if(i+8<=n && s[i] == \'h\' && s[i+1] == \'a\' && s[i+2] == \'p\' && s[i+3] == \'p\' && s[i+4] == \'i\' && s[i+5] == \'n\'&& s[i+6] == \'e\' && s[i+7] == \'s\' && s[i+8] == \'s\') 
            {
                gg = 1;
            }
            if(1+8<=n && s[1] == \'h\' && s[2] == \'a\' && s[3] == \'p\' && s[4] == \'p\' && s[5] == \'i\' && s[6] == \'n\'&& s[7] == \'e\' && s[8] == \'s\' && s[9] == \'s\') 
            {
                gg = 1;
            }
            if(gg == 0)
            {
                printf("%d %d\\n", 1, i);
                return 0;
            }
            swap(s[1], s[i]);
        }
    }

    if(v.size() == 1)
    {
        printf("YES\\n");
        printf("%d %d\\n", v[0], v[0]+1);
    }

    if(v.size() == 2)
    {
        printf("YES\\n");
        printf("%d %d\\n", v[0], v[1]+1);
    }

    if(v.size() > 2)
    {
        printf("NO\\n");
    }
}

code2: 待补。。。

 

 

 

 

C.

题意:给a个红球,b个绿球,c个不知道颜色的球,问,保证拿出的球中,红球

不超过n,绿球不超过m,最多能拿几个球。 

solve: 比赛时读错题了,懵逼了半天。

如果a+c>n,那么拿n+1个球有可能GG.

如果b+c>m,那么拿m+1个球有可能GG.

 

code:

#include <iostream>
using namespace std;
typedef long long LL;
LL ans = 0;
int main()
{
    LL a, b, c, m, n;
    cin >> a >> b >> c >> n >> m;
    ans = a + b + c;
    if(a+c > n) ans = min(n, ans);
    if(b+c > m) ans = min(m, ans);
    cout << ans << endl;
}

 

D.

题意:一只蛤,在一根线上跳,每次可以跳的距离给出了,问能否跳到目标。

坑点:负数和0的特判

#include <iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b)
{
    return b==0?a:gcd(b, a%b);
}
int n;
LL x, ans, k;
int main()
{
    cin >> n >> k;
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d", &x);
        if(x<0) x = -x;
        if(i==1) ans = x;
        if(x==0) continue;
        ans = gcd(ans, x);
    }
    if(k % ans == 0) cout << "YES";
    else cout << "NO";
}

 

E.

题意:数轴上有n个可以互相传送的点,和m个宝石。移动1个距离,-1s,传送门之间相互传送不消耗时间

问吃完所有宝石最小耗费。

 

solve:

hint 1:离散化.

hint 2:传送门i与传送门(i+1)之间的宝石,有2种处理方式。

a) 从一个门直接移动到另一个门。时间耗费为| p[i+1]-p[i] |.

b) 相邻宝石最大间距为maxlen,时间耗费为 2 * (| p[i+1]-p[i] |  -  maxlen).

画个图,更好理解!

 

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const int NICO = 200000 + 10;
int n, m;
LL t[NICO], b[NICO];
vector<LL> v; 
map<LL, int> mp;
int main()
{
    scanf("%d %d", &n, &m);
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d", &t[i]);
        v.push_back(t[i]);
    }
    t[0] = -1e16, t[n+1] = 1e16;
    int pos = 1;
    for(int i=1;i<=m;i++)
    {
        scanf("%I64d", &b[i]);
        v.push_back(b[i]);
    }
    sort(v.begin(), v.end());

    for(int i=0;i<v.size();i++)
    {
        mp[v[i]] = i;
    }
    LL ans = 2L * (v[v.size() - 1] - v[0]);
    for(int i=1;i<n;i++)
    {   
        int l = mp[t[i]], r = mp[t[i+1]];
        LL mx = 0;
        for(int j=l;j<r;j++)
        {
            mx = max(mx, v[j+1] - v[j]);
        }
        mx = mx*2L;
        mx = max(mx, t[i+1] - t[i]);
        ans -= mx;
    }   
    cout << ans << endl;
}   

 

F.

 

G.

题意:gay里gay气的CF...... 一群人,如果A对B产生了爱慕之情,A就将自己的name改成I_love_B.

按时间顺序给出了一些爱慕的关系,问1号,最终的name是什么。

题解:逆向来一遍就行了。

#include <iostream>
using namespace std;
const int NICO = 200000 + 10; 
int n, m, u, v;
char s[NICO][40];
int a[NICO], b[NICO];
int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s", s[i]);
    }
    scanf("%d", &m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d", &a[i], &b[i]);
    }
    int need = 1;
    for(int i=m;i>=1;i--)
    {
        if(a[i] == need)
        {
            printf("I_love_");
            need = b[i];
        }
    }
    printf("%s\\n", s[need]);

}

 

H.

题意:一个矩阵,拿掉一个十字架(莫名想到硫磺火),让剩下的数字中最大值最小,求最小值~

题解:预处理,求出每个元素左上,左下,右上,右下最小值。

#include <iostream>
using namespace std;
const int NICO = 1002;
int n, m;
int a[NICO][NICO], l[NICO][NICO], r[NICO][NICO];
int lu[NICO][NICO], ld[NICO][NICO], ru[NICO][NICO], rd[NICO][NICO];
int main()
{
    scanf("%d %d", &n, &m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d", &a[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) 
        {
            l[i][j] = max(l[i][j-1], a[i][j]);
        }
        for(int j=m;j>=1;j--)
        {
            r[i][j] = max(r[i][j+1], a[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            lu[i][j] = max(l[i][j], lu[i-1][j]);
            ru[i][j] = max(r[i][j], ru[i-1][j]);
        }
    }
    for(int i=n;i>=1;i--)
    {
        for(int j=1;j<=m;j++)
        {
            ld[i][j] = max(l[i][j], ld[i+1][j]);
            rd[i][j] = max(r[i][j], rd[i+1][j]);
        }
    }
    int ans = 1e9+7, cx = -1, cy = -1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int t1 = max(lu[i-1][j-1], ru[i-1][j+1]);
            int t2 = max(ld[i+1][j-1], rd[i+1][j+1]);
            int t3 = max(t1, t2);
            if(t3 < ans)
            {
                cx = i, cy = j;
                ans = t3;
            }
        }
    }
    printf("%d %d\\n", cx, cy);
}

I.

 

J.  (炒鸡好玩的一道题)

题意:给一颗树,两个人准备制定好路线,准备抓一个怪物,这个怪物跑得很快。

并且知道了两人路线。问有没有可能抓到怪物。

 

题解:

hint 1: A守住重要隘口,B遍寻涯角~ 这就是我们大致的思路。

 

图画的好恐怖。。。。。。。。。。。。。。。

A守住1,然后B把两个圈圈里面的点扫一遍即可。

 

 

hint 2: 然后我们发现,A要守的节点必须是链状的。B要访问的每一个分支,也

得是链状的。

 

有趣的结论:从叶子节点向上删点,删到出现岔路为止。然后判断接下来的剩下的

图是不是一根链即可。

 

code:

 1 #include <iostream>
 2 #include <vector>
 3 #include <set>
 4 using namespace std;
 5 const int NICO = 200000 + 10;
 6 int n, u, v, deg[NICO], flag[NICO];
 7 vector<int> vec[NICO];
 8 void dfs(int x, int p)
 9 {
10     flag[x] = 1;
11     for(int i=0;i<vec[x].size();i++)
12     {
13         if(vec[x][i] == p) continue;
14         if(deg[vec[x][i]] <= 2)
15         {
16             dfs(vec[x][i], x);
17         }
18     }
19 }
20 int main()
21 {
22     scanf("%d", &n);
23     for(int i=1;i<n;i++)
24     {
25         scanf("%d %d", &u, &v);
26         vec[u].push_back(v);
27         vec[v].push_back(u);
28         deg[u] ++, deg[v] ++;
29     }
30     for(int i=1;i<=n;i++)
31     {
32         if(deg[i] > 1) continue;
33         int t = i; dfs(t, -1);
34     }
35 
36     for(int i=1;i<=n;i++)
37     {
38         if(flag[i]) continue;
39         int cnt = 0;
40         for(int j=0;j<vec[i].size();j++)
41         {
42             if(flag[vec[i][j]]) continue;
43             cnt ++;
44         }
45         if(cnt >= 3)
46         {
47             printf("NO\\n");
48             return 0;
49         }
50     }
51     printf("YES\\n");
52 
53 }

 

 

 

K.

 

L.

 

M.

贪心!每次选GG的人从最后面拿,为前面腾出空间即可。

#include <iostream>
#include <vector>
using namespace std;
const int NICO = 200000 + 10;
typedef long long LL;
LL sum = 0;
int a[NICO], n;
vector<int> v1, v2;
int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d", &a[i]);
        sum += a[i];
    }
    if(sum > n)
    {
        printf("NO\\n");
        return 0;
    }
    int ok = 1;
    int pos = n;
    for(int i=n;i>=1;i--)
    {
        if(a[i] > 0)
        {
            for(int j=pos;j>=pos-a[i]+1;j--)
            {
                if(i >= j) ok = 0;
                v1.push_back(i);
                v2.push_back(j);
            }
        }
        pos = pos-a[i];
    }
    if(ok == 0)
    {
        printf("NO\\n");
        return 0;
    }
    printf("YES\\n");
    for(int i=0;i<v1.size();i++)
    {
        printf("%d %d\\n", v1[i], v2[i]);
    }
}

 

以上是关于Gym101341题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Gym101341I:Matrix God(随机化构造矩阵降维)***

gym101666题解

Gym102361A Angle Beats(直角三角形 计算几何)题解

Pursuing the Happiness

Matrix God 随机化构造矩阵降维

codeforces gym102040 前四题签到题解