2018年成都信息工程大学第七届ACM程序设计竞赛 题解报告

Problem A(读信)

签到题:
把所有字母全部转换成大写(或小写), 然后判断一下是否是回文串(正着和倒着是否完全相等)就可以了
时间复杂度: O ( n )

Problem B(Anxdada的询问1)

签到题:

for(int i=1;i<n;++i)
    for(int j=i+1;j<=n;++j)
        if(a[i]+a[j]==2*m)
            ++ans;

注意: 使用(a[i]+a[j])/2==m可能会出问题: (int/int==int)
时间复杂度: O ( n 2 )

Problem C(Anxdada的询问2)

简单题:
考虑每一个数字 a [ i ] ( 1 i n ) , 能和 a [ i ] 组成平均数为 m 的数为 ( 2 m a [ i ] )
所以枚举每一个 a [ i ] , 统计一下数字 ( 2 m a [ i ] ) 的个数就好了
统计数字个数:
解法1: C++STL库的map<int,int>
(由于牛客没有开O2优化, 所以很慢: 1300ms左右, 没有卡这种做法)
解法2: 二分查找
对数组 a 排序, 通过二分查找: 找到数组中第一个 a [ i ] 的数字的下标 x , 再通过二分查找出第一个 > a [ i ] 的数字的下标 y , ( y x ) 就是数字 a [ i ] 的出现次数
(快如闪电, 200ms左右)
注意: 为了避免重复计算, 由于平均数等于m的2个数一定: 其中一个 m , 另外一个 m , 所以统计 a [ i ] m 的一部分就好了, 再特殊处理一下 a [ i ] = m 的情况
时间复杂度: O ( n l o g n )

Problem E(mengxiang000的龙)

计算几何(初中数学):
相信大家都学过”将军饮马”问题, 这道题就是 借鉴来的

作: 家关于河流的对称点: 家’, 所以家’与学校的连线与河流的交点就是答案

做法1: 寄蒜几盒(计算几何)硬做, 时间复杂度 O ( 1 )
做法2: 推公式
(无损精度的公式如下)
A = ( b 2 a 2 ) x 1 2 a b y 1 + 2 a c
B = ( a 2 b 2 ) y 1 2 a b x 1 + 2 b c
C = a 2 + b 2
D = C x 2 A
E = C y 2 B
F = E b x 2 + D ( c b y 2 )
G = D a y 2 + E ( c a x 2 )
H = a D + b E
答案就是 ( F H , G H )
时间复杂度 O ( 1 )
做法3: 三分查极值(略), 时间复杂度 O ( l o g n )

Problem F(fold的游戏)

思维题:
这道题直接输出: “plp win”就行了(想不到吧!)
证明:
设: 题目中的游戏为 G 1
我们对游戏 G 1 加上一个限制条件, 不能选1这个数字, 这样形成了一个新游戏 G 2
如果对于某一个确定的 n 0 , 游戏 G 2 一定存在某种策略, 要么先手必胜, 要么后手必胜
对于某一个确定的 n 0 , 游戏 G 2 如果先手必胜, 那么游戏 G 1 先手也一定能取得胜利, 因为1是所有数字的约数, 选中任意一个不为1的数字以后就不能再选1; 游戏 G 2 如果后手必胜, 那么游戏 G 1 的先手选1, 那么 G 1 的先手将变成游戏 G 2 的后手, 也能够取得胜利, 所以先手必胜
时间复杂度 O ( 1 )

Problem G(EL_PSY_CONGROO)

这道题就是在DAG(有向无环图)中找起点到终点的路径的条数
拓扑排序的过程中维护一下方案数+
注意: 答案取模(余)以后等于0, 答案不一定是不可达

Problem H(陈犇的数学题)

数学题:
这里的向下取整符号 x 是骗人的, 因为答案始终都是整数

(1) f ( n ) = 0 + ( e x x n 1 ) d x (2) = 0 + x n 1 d ( e x ) (3) = ( ( e x x n 1 ) | 0 + 0 + e x d ( x n 1 ) ) ( ) (4) = x n 1 e x | 0 + + 0 + e x d ( x n 1 ) ) (5) = 0 + e x d ( x n 1 ) (6) = ( n 1 ) 0 + ( e x x n 2 ) d x (7) = ( n 1 ) f ( n 1 )

由于 f ( 1 ) = 1 , 所以 f ( n ) = ( n 1 ) ( n 2 ) 2 1 = ( n 1 ) !
由于答案对 1000003 取模(余), 所以当 n 1000004 时一定包含因子 1000003 , 此时答案为 0
n < 1000004 时, 循环计算就可以了
由于有多个询问, 所以需要预处理出 n ! 阶乘, 然后 O ( 1 ) 的回答每个询问就好了
时间复杂度 O ( q )

Problem J(twh233打方块)

模拟题:
处理出所有方块(及其旋转)的19种情况, 然后按照题意模拟即可
时间复杂度: O ( 写就能过 )
标程:

#include<bits/stdc++.h>
using namespace std;

struct block
{
    bool a[5][5];
    int l,r;
    block() {memset(a,0,sizeof(a));}
};

vector<block>G;

void make(int b,int c,int d,int e,int f,int g,int h,int i,int l,int r)
{
    block x;
    x.a[b][c]=1,x.a[d][e]=1;
    x.a[f][g]=1,x.a[h][i]=1;
    x.l=l,x.r=r;G.push_back(x);
}

void init()
{
    make(1,1,1,2,1,3,1,4,1,4);
    make(1,1,2,1,3,1,4,1,1,1);

    make(1,1,2,1,2,2,2,3,1,3);
    make(1,1,1,2,2,1,3,1,1,2);
    make(1,1,1,2,1,3,2,3,1,3);
    make(1,2,2,2,3,2,3,1,1,2);

    make(2,1,2,2,2,3,1,3,1,3);
    make(1,1,2,1,3,1,3,2,1,2);
    make(1,1,1,2,1,3,2,1,1,3);
    make(1,1,1,2,2,2,3,2,1,2);

    make(1,1,1,2,2,1,2,2,1,2);

    make(1,2,1,3,2,1,2,2,1,3);
    make(1,1,2,1,2,2,3,2,1,2);

    make(1,1,1,2,2,2,2,3,1,3);
    make(1,2,2,1,2,2,3,1,1,2);

    make(1,2,2,2,2,1,2,3,1,3);
    make(1,2,2,1,2,2,3,2,1,2);
    make(1,1,2,1,3,1,2,2,1,2);
    make(1,1,1,2,1,3,2,2,1,3);
}

char a[20][15];

int down(int i,int j)
{
    int l=j,r=j+G[i].r-1;
    for(int k=1;;k++)
        for(int x1=1,x2=k;x1<=4; x1++,x2++)
            for(int y1=1,y2=l;y1<=G[i].r && y2<=r;y1++,y2++)
                if(G[i].a[x1][y1] && a[x2][y2]=='#')
                    return k-1;
}

void add(int i,int j,int k,bool op)
{
    int l=j,r=j+G[i].r-1;
    for(int x1=1,x2=k;x1<=4; x1++,x2++)
        for(int y1=1,y2=l;y1<=G[i].r && y2<=r;y1++,y2++)
            if(G[i].a[x1][y1])
                a[x2][y2]=op?'#':'*';
}

int cal()
{
    int res=0;
    for(int i=1;i<=15;i++)
    {
        bool flag=true;
        for(int j=1;j<=10;j++)
            if(a[i][j]=='*')
                flag=false;
        if(flag)res++;
    }
    return res;
}

int main()
{
    init();
    for(int i=1;i<=15;i++)scanf("%s",a[i]+1);
    for(int i=1;i<=10;i++)a[16][i]='#';
    int ans=0;
    for(int i=0;i<G.size();i++)
        for(int j=1;j+G[i].r<=11;j++)
        {
            int k=down(i,j);
            add(i,j,k,true);
            ans=max(ans,cal());
            add(i,j,k,false);
        }
    return !printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/fo0Old/article/details/80216004
今日推荐