HZOI0722 NOIp考试报告



写在前面:

我头好痛



 考试概况:

T1:数论  tps:60   耗时:1h

T2:数论+组合数学  tps:0  耗时:10min

T3:二分图   tps:60  耗时:2h

sum : 120    rank:13

暴力分其实还能多写30 > . <



T1 方程的解

数论一直学的很死,记得扩欧会出负数,然后就傻了,不会,直接跳题



 

T2 visit 

一眼组合数学,然后不会写~~~~(其实是自己根本不会组合)

对于30分,dp[走到哪行][走到哪列][花了几步],记得处理好循环上限。

正解是,对于T=n+m的情况,看为在n+m步中挑n步为横着走,答案为C(n+m,n),然后接着往下想,对于多出来的步数要怎么办呢?

因为不能站着不动,所以只能左右横跳或者上下横跳(?)来抵消步数,如果T-n-m为奇数,则不可能停在目标点,直接去掉

对于每多出来的两步,可以选择加一组上下或者一组左右,枚举再进行下一步处理

把路径拆成向各个方向移动的步数,然后就是一个简单的组合数问题

那这跟数论有啥关系啊?

有,因为他很巧(e)妙(xin)地把40%的数据中的模数变为了几个不同质数的乘积

最后要来个中剩(太恶毒了,衡水rank1大哥居然还A了,非人哉)

代码我可以咕咕咕吗



T3 CF274E mirror room

这是一道好题,但是我不会写> . <

很棒的事情是有60分的暴力分,然后我写了一个头都晕了的大暴力

#include<bits/stdc++.h>

using namespace std ;

const int MAXN = 2050;
int n,m,k,sx,sy,dir;
int dx[5] = {0,-1,1,1,-1},dy[5] = {0,1,1,-1,-1};
int cx1[5] = {0,0,-1,0,1},cy1[5] = {0,-1,0,1,0};
int cx2[5] = {0,1,0,-1,0},cy2[5] = {0,0,-1,0,1};
int fd0[5] = {0,3,4,1,2},fd1[5] = {0,2,3,4,1},fd2[5] = {0,4,1,2,3},fd3[5] = {0,3,4,1,2};
int nx1[5] = {0,0,1,0,-1} , ny1[5] = {0,1,0,-1,0},nx2[5] = {0,-1,0,1,0} , ny2[5] = {0,0,1,0,-1};
bool book[MAXN][MAXN][5],blo[MAXN][MAXN];

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++){
        int xx,yy;
        cin>>xx>>yy;
        blo[xx][yy] = 1;
    }
    char direc[5]; 
    cin>>sx>>sy;
    cin>>direc;    
    if(direc[0] == 'S' && direc[1] == 'E') dir = 2;
    if(direc[0] == 'S' && direc[1] == 'W') dir = 3;
    if(direc[0] == 'N' && direc[1] == 'E') dir = 1;
    if(direc[0] == 'N' && direc[1] == 'W') dir = 4;
    for(int i=0;i<=n+1;i++){
        blo[i][0] = blo[i][m+1] = 1;
    }
    for(int i=0;i<=m+1;i++){
        blo[0][i] = blo[n+1][i] = 1;
    }
    while(1){
        if(book[sx][sy][dir]) break;
        book[sx][sy][dir] = true;
        if(blo[sx+dx[dir]][sy+dy[dir]]){
            bool flag1=blo[sx + dx[dir] + cx1[dir]][sy + dy[dir] + cy1[dir]];
            bool flag2=blo[sx + dx[dir] + cx2[dir]][sy + dy[dir] + cy2[dir]];
            if(flag1 && flag2) dir = fd3[dir];
            else if(flag1 && !flag2) sx += nx1[dir],sy += ny1[dir],dir = fd1[dir];
            else if(!flag1 && flag2) sx += nx2[dir],sy += ny2[dir],dir = fd2[dir];
            else if(!flag1 && !flag2) dir = fd0[dir];
            
        }
        else sx+=dx[dir],sy+=dy[dir];
    }
    int ans = 0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(blo[i][j]) continue;
            for(int k=1;k<=4;k++){
                if(book[i][j][k]){
                    ans++;
                    break;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

百万手码数组

正解瞎看了看,不知道为什么复杂度是对的> . <

为了方便思考我们以格子中心为思考对象

首先区别两种反射方式:斜路反射(方向和所在格子都改变的3)和回路反射(只改变方向的2 4)

(第一种不算反射)

将图染色,有邻边的方格染不同颜色,染成黑白,显然光线不经过斜路反射无法到达另一种颜色的路径,

然后因为从一个格点到另一个格点时,格点的横纵坐标之和不变,一个小格子的两对对角点奇偶性不同,

所以一个格子只有两种经过方式(斜入斜出)

 如果模拟每次反射,由上面的结论易得复杂度最坏为O(n+m+k),这很好。

在一次循环内统计在下一次斜路反射前经过多少格子,如果出现了回路反射证明原来起点的反方向也可以来一遍,

不断统计答案(也许题解是这个意思?)

TAG:SIN_XIII ⑨

猜你喜欢

转载自www.cnblogs.com/SINXIII/p/11225498.html