2020 ICPC Shanghai Site(三个签到题B G M)

2020 ICPC Shanghai Site

B(思维)

题意:扫雷游戏,给定n*m的矩阵两个A和B ,每个矩阵中,‘.’代表这个位置没有东西,‘X’代表这个位置有个地雷,’.‘的分数是以该点为中心的九宫格内所有的雷的数量,整个矩阵的总分是所有’.'的分数总和。

现在我们希望让A和B两个矩阵的分数一样,我们可以改变B矩阵最多不超过n*m/2个点(雷变空or空变雷)。请输出改变后的B矩阵。

思路:一开始我们觉得这个题貌似是一个贡献题,就是算算X的贡献,后来注意到这个鬼数据:n*m/2

我们觉得这么多改变的次数必定有诈,所以试着暴力修改:把所有不一样的点都改成和A一样。但是显然这样不行,但是如果B一开始和A矩阵不一样的点大于nm/2个,那么把A矩阵每个元素都改变得到了A矩阵的逆,就应该有这样的结论:如果A矩阵的B矩阵的不同点个数大于nm/2,那么A的逆矩阵和B的不同点个数一定小于等于n*m/2。

所以输出的就只有两种情况:
1.输出A矩阵
2.输出A的逆矩阵

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e3+100;
char a[N][N];
char b[N][N];
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>b[i][j];
    int cnt=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]!=b[i][j])
                cnt++;
    int lim=(n*m)/2;
    if(cnt>lim)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i][j]=='.')
                    cout<<"X";
                else
                    cout<<".";
            }
            cout<<endl;
        }
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cout<<a[i][j];
            }
            cout<<endl;
        }
    }
    return 0;
}

G(数学规律,公式)

题意:我们有一个长度为n的斐波那契数列,在求出这个公式的值:请添加图片描述

思路:
1.每三项就有一个偶数,所以偶数的个数是n/3
2.每个奇数都可以和每个偶数组合一次,所以方案数有(n-n/3)*(n/3)
3.偶数之间互相组合,推出规律为n *(n-1)/2
所以总方案数为:(n-n/3) *(n/3)+n/3 *(n/3-1)/2

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+100;
signed main()
{
    int n;
    cin>>n;
    int temp=n/3ll;
    cout<<(n-n/3ll)*(n/3ll)+(temp*(temp-1ll))/2ll;
    return 0;
}

M(思维,暴力or树的遍历)

题意:给了一堆文件路径,其中前n个文件路径是可以折叠的,后面的m个文件路径不可以折叠,问你折叠之后还剩多少个文件路径

两种做法
1.把不能折叠的路径每一个路径都标记,然后在遍历n个路径的时候检查当前遍历到的路径节点是否被标记为不可折叠,如果是,并且到这个节点之前没有计算过,那么就让答案数加一并且标记一下这个节点被遍历过了。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 200;
map<string,bool>mp,vis;
string a[N];
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    for(cin>>t;t;t--)
    {
        mp.clear();vis.clear();
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        for(int i=1;i<=m;i++)
        {
            string s;
            cin>>s;
            string temp="";
            for(int j=0;j<s.length();j++)
            {
                temp+=s[j];
                if(s[j]=='/'||j==s.length()-1)
                {
                    mp[temp]=1;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            string temp="";
            for(int j=0;j<a[i].length();j++)
            {
                temp+=a[i][j];
                if(a[i][j]=='/'||j==a[i].length()-1)
                {
                    if(vis[temp])
                        break;
                    else if(!mp[temp])
                    {
                        vis[temp]=1;
                        ans++;
                        break;
                    }
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

第二个,给个思路,代码就不写了

我们用类似于字典树的方法来生成这些文件夹的字典树,只不过把字典树的字符换成了字符串(利用map即可完成),然后读入m个不可折叠的文件路径的时候就在树上跑,所经过的点都打上结束标记。做完这些之后只需要统计字典树的叶子节点就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值