2020ICPC上海站补题

B - Mine Sweeper II

题目大意:
一个 n × m n×m n×m的图,图上只有两种字符: X X X . . . X X X表示这个地方是雷, . . .表示这个地方没有雷,并且这个地方有一个表示这个地方的周围8个点有几个雷的数字cnt。
现在有A,B两个n和m相同的图,问能否改变小于等于 n ∗ m / 2 n*m/2 nm/2个点,让A,B两个图中的cnt相等,如果可以,随便输出一个改变之后的B图,如果没有的话,输出-1。

开始的时候没什么想法,n,m都不会超过1000。后来这个题过的人越来越多,我试了几个样例,有点猜的那个意思,是不是先统计一下俩图的不一样的个数,要是小于等于 n ∗ m / 2 n*m/2 nm/2,就直接输出A,要是超过了,就输出A翻转之后的。当时因为这个结论有点猜的意思,就一直在想如果这样的话那什么时候输出-1。因为是训练赛,就先交了一发,觉得wa了就wa了,那就再写,谁知道,,过了。
后来想了想,一个地雷对于他对他周围的空白格的影响等价于把他周围的空白格都变成雷,自己变成空白格的的影响,也就是说,这个把这个图置反(雷变空白,空白变雷),和原图其实是一样的。而且题目说,最多可以进行 n ∗ m / 2 n*m/2 nm/2次转换操作,那么B图必然可以转化成A图或A的反,也就是说,不存在 -1 的情况,所以只要把反图求出来,然后看看 A 或者 A的反图 哪个转换成B的次数小于 n ∗ m / 2 n*m/2 nm/2, 那个图就行了。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;
typedef long long ll;

const int maxn=1005;
int main()
{
    char A[maxn][maxn];
    char B[maxn][maxn];

    int n,m;
    scanf("%d %d",&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++;
            }
        }
    }
    if(cnt>=n*m/2)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(A[i][j]=='.')
                    printf("X");
                else
                    printf(".");
            }
            printf("\n");
        }
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cout<<A[i][j];
            }
            printf("\n");
        }
    }
    return 0;
}

G - Fibonacci

题目大意
比如说给一个斐波那契数列
1 1 2 3 5 8 13 21
那么本题让求的就是1后面与它相乘为1的个数+1后面与它相乘为1的个数+2后面与它相乘为1的个数+3后面与它相乘为1的个数+5后面与它相乘为1的个数+…+21后面与它相乘为1的个数,又因为题目中规定当x*y时偶数的时候,g(x,y)=1,否则为0。斐波那契数列的特点是分列呈“奇奇偶”排列。

代码:

#include <iostream>

using namespace std;
typedef long long ll;

int main()
{
    ll n;
    scanf("%lld",&n);
    ll ou=n/3;
    ll ji=n-ou;

    ll ans=0;
    ans+=ou*(1+ou)*2/2;  //奇数

   //   cout<<ans<<endl;
   /* int ouu=ou;
    for(int i=1;i<=ou;i++)
    {
        ouu--;
        ans+=3*ouu;
    }*/
    ans+=(ou-1)*ou*3/2;


    if(n%3!=0)
    {
        ans+=ou*(n%3);
    }

    printf("%lld\n",ans);

    return 0;
}

I - Sky Garden

题目大意
给你一个 n,给你一个m,n表示有n个圆套在一起,圆心都是(0,0),半径是1~n,m指的是m条线来把这个图形平均分成2m份,然后这个时候线和圆会有交点,问你任意两个交点之间的距离最小是多少。要求是必须沿着存在的线走。

我的写法是这样的
首先,因为圆心到其他所有点的距离是固定的,所以,可以单独求出来,对于圆心到每一层的同一位置的点,距离是1+2+…+n,也就是(1+n)×n/2,又因为除了圆心之外,有2m个点,也就是(1+n)×n/2×2×m。但这个地方要注意,当m是1的时候,是没有圆心的!!!特判一下就行。
其他的我选择的是两层for暴力的做,两层之间,相邻层枚举,比如3层的a点到2层所有点的距离,先看3层a点到2层b点距离吧,可能有两种情况,一种是直接走直径过去(不一定非要是正相对),一种是走一截弧再走一下这两层的距离,所以这个时候二者取最小的就可。附上一个图。因为这是对于3层a点到2层b点距离,因为这个点的距离都是对称的,所以在这个图里面3层a点到2层b点距离确定了之后,b的对称点的那个c点距离是相等的,乘二就可。
在这里插入图片描述
大概就这个思路,具体看代码吧。

代码

#include <bits/stdc++.h>

using namespace std;

const double PI=acos(-1);
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    double ans=0;
   // ans=(1+n)*n/2*2*m; //第一圈;
    for(int i=1;i<=n;i++)
    {
        double now=0;
        double l=2*PI*i/(2*m);  //弧长
        for(int j=i;j<=n;j++)
        {
            now=0;
            now+=abs(j-i);
            for(int k=1;k<=m-1;k++)  //同一圈点的个数
            {
                double a=l*k+abs(j-i);  //弧加半径
                double b=i+j;  //直接走直径
                now+=min(a,b)*2; //两种策略取小的
            }
            now+=i+j;
            if(j==i)
            ans+=now*m;
            else
            ans+=now*2*m;
        }
    }
    if(m!=1)
    ans+=(1+n)*n/2*2*m; //第一圈;
    printf("%.10f\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值