Noip模拟考试八:解题报告

1. 鼎纹
(grain.cpp/.c/.pas)
【问题描述】
据说鼎纹的 种制造 式是 铜模印出来的,这是我国古代劳动 智慧
的结晶。铜模印过的地 ,会留下深深的印记,经过时间的炼化,洗
练成历史的遗存。
聪明的古代劳动人民拥有一个 a 行 b 列的铜模,每个位置要么是 0(代表
这个点是平的),要么是 1(代表这个点是凸起的)。他们想造 个 n 行 m 列
的鼎 ,其中每个位置也都是 0 或 1,表示经过若干 次印后,每个位置的结果。
有一些要求。铜模是不能旋转和翻转的;在印的过程当中,铜模的凸起不
能出现在鼎面的外面(平的部分是可以出现在外面的),鼎面上的同一个位置
不能被多个凸起印下(在任意两次印时,鼎面上不存在一个点,使得这两次都
有铜模上为 1 的点覆盖它)。
请你判断这个鼎面能不能被印出来。
【输入格式】
输入文件件名为 grain.in。
本题多测。
第一行,一个整数 T ,表示测试
点数量。接下来 T 个测试点,每
个测试点中:
第一行包含 4 个整数 n,m,a,b。
接下来 n 行 ,每行 m 个字符,描述鼎面 。“0”表示
平,“1”表示凸起。接下来 a 行,每行 b 个字符,
描述铜模。“0”表示平,“1”表示凸起。
【输出格式】
输出 件名为 grain.out。
共有 T 行 ,对于每个测试点,输出 “YES”(能)或“NO”(不能)。

(大模拟)

思路就是在鼎上找到一个为'1'的点,然后用模版对应,循环此操作。

注意对模版进行预处理,记录每一个1对于第一个1的相对位置。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1010
#define maxm 10000005
int a[maxn][maxn],ecnt,cnt,m,n,d,b;
int x1[maxm],y1[maxm],x2[maxm],y2[maxm];
char str[maxn];
bool check(int x,int y)
{
    a[x][y]=0;
    int tx,ty;
    for(int i = 1 ; i < ecnt ; ++i)
    {
        tx=x+x2[i];ty=y+y2[i];
        if(tx<1||ty<1||tx>n||ty>m||!a[tx][ty])return false;
        a[tx][ty]=0;
    }
    return true;
}
void solve()
{
    cnt=ecnt=0;
    memset(a,0,sizeof(a));
    scanf("%d%d%d%d",&n,&m,&d,&b);
    for(int i = 1 ; i <= n ; ++i)
    {
        scanf("%s",str+1);
        for(int j = 1 ; j <= m ; ++j)
            if(str[j]=='1'){x1[++cnt]=i;y1[cnt]=j;a[i][j]=1;}
    }
    for(int i = 1 ; i <= d;++i)
    {
        scanf("%s",str+1);
        for(int j = 1 ; j <= b ; ++j)
            if(str[j]=='1'){x2[ecnt]=i;y2[ecnt++]=j;}
    }
    for(int i = 1 ; i <ecnt ; ++i)
        {
            x2[i]-=x2[0];
            y2[i]-=y2[0];
        }
    for(int i = 1 ; i <= cnt ; ++i)
        if(a[x1[i]][y1[i]])
            if(!check(x1[i],y1[i]))
            {
                printf("NO\n");
                return ;
            }
    printf("YES\n");
}
int main()
{
  //  freopen("grain.in", "r", stdin);
 //   freopen("grain.out", "w", stdout);
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

2. 看球赛
(football.cpp/.c/.pas)
2200 年 里奥迪奥带领的十星巴西对战莱昂纳多带领的阿根廷的世界杯决赛马
上开始了!前来在巨型球场观看比赛的观众数不甚数,但是由于突如其来的系统
原因,大家不能网上购票,只能到售票窗口,排成长龙买票.
按售票处规定,每一个限购一张门票,且每一张门票 50 美元。 在排成长龙的球
迷中有 n 个人手持 50 美元,另外有 n 个人手持 100 美元。假设售票处开始的时
候没有零钱,试问这 2n 个球迷有多少种排队方式使得售票处不会出现找不出钱
的尴尬局面,导致拖延球迷看球时间。
【输入与输出说明】
输入两行,第一行一个正整数 T,表示数据个数。
第二行有 T 个正整数,n1,n2,....nT.
输出 T 行,每一行为被 10^9+7 模过的结果。

枚举前几项就很明显了,卡特兰数。(然鹅对于一个之前不会卡特兰数的蒟蒻来说简直难炸了 老师总喜欢考一些大家没学过的东西qwq)

然后快速幂求逆元,结束。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define mod 1000000007
using namespace std;
int n;
ll ksm(ll x,int b)
{
    ll fu(1);
    while(b)
    {
        if(b&1)fu=fu*x%mod;
        b>>=1;
        x=x*x%mod;    
    }
    return fu;
}
void solve()
{
    ll ret(1);
    ll rret(1);
    scanf("%d",&n);
    int m=n<<1;
    for(int i = 1 ; i <= n ; ++i)
        {
            rret=rret*(m-i+1)%mod;
            ret=ret*i%mod;
        }
    ret=ret*(n+1)%mod;
    ll ans=rret*ksm(ret,mod-2)%mod;
    printf("%I64d\n",ans);
}
int main()
{
    //freopen("football.in","r",stdin);
    //freopen("football.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}
 

靶形数独
(sudoku.cpp/.c/.pas)
【题目描述】
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,
Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格
高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些
数字,利用逻辑推理,在其他的空格上填入 1 到 9 的数字。每个数字在每个小九宫格内不

重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。
上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8 分,蓝色区域外面一圈
(棕
色区域)每个格子为 7 分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。比赛

要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游
戏规定,将以总分数的高低决出胜负。
由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。

 

加强版八数码,代码借鉴hzwer大佬。

暴力搜索即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define searchnext(x,y) y==8?dfs(x+1,0):dfs(x,y+1)
using namespace std;
bool visx[10][10],visy[10][10],vis[5][5][10];
int a,b[10][10];
int getscore[10][10][10];
int ans=-1,score;
int cul(int x,int y,int s)
{
    if(x==4&&y==4)return 10*s;
    if(x>=3&&y>=3&&x<=5&&y<=5)return 9*s;
    if(x>=2&&y>=2&&x<=6&&y<=6)return 8*s;
    if(x>=1&&y>=1&&x<=7&&y<=7)return 7*s;
    return 6*s;
}
bool fillin(int x,int y,int k)
{
    if(visx[x][k]||visy[y][k]||vis[x/3][y/3][k])return false;
    visx[x][k]=visy[y][k]=vis[x/3][y/3][k]=1;
    b[x][y]=k;
    score+=getscore[x][y][k];
    return true;
}
void del(int x,int y,int k)
{
    visx[x][k]=visy[y][k]=vis[x/3][y/3][k]=0;
}
void dfs(int x,int y)
{
    if(x==9&&y==0)
    {
        ans=max(ans,score);
        return ;
    }
    if(b[x][y])searchnext(x,y);
    else 
    {
        for(int i = 1 ; i <= 9 ; ++i)
        {
            int t=score;
            if(fillin(x,y,i))
            {
                searchnext(x,y);
                del(x,y,i);
                score=t;
            }
        }
        b[x][y]=0;
    }
}

int main()
{
   // freopen("sudoku.in","r",stdin);
   // freopen("sudoku.out","w",stdout);
    for(int i = 0 ; i < 9 ; ++i)
        for(int j = 0 ; j < 9 ; ++j)
            for(int k = 1 ; k <= 9 ; ++k)
                getscore[i][j][k]=cul(i,j,k);
    for(int i = 8;i >= 0 ; --i)
        for(int j = 8 ; j >= 0 ; --j)
            {
                scanf("%d",&a);
                if(a)fillin(i,j,a);
            }
    dfs(0,0);
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-08-19 17:10  傅judge  阅读(216)  评论(0编辑  收藏  举报