洛谷P3585 [POI2015]PIE

传送门

题目大意:有个n*m的格子图,要求‘x‘点要被染成黑色

有个a*b的印章,‘x‘是可以染色的印章上的点。

要求用印章去染色格子

(1)印章不可以旋转。

(2)不能把墨水印到纸外面。

(3)纸上的同一个格子不可以印多次。

题解:模拟

从题目中可以看出,一定要让印章的左上角对应目前n*m方

格中未染色的左上角。因为要求不能重复染色,可以每染完

一个格子就把它赋值为0.(待染色为1)。

开始纯模拟,没有任何优化的代码。

加了个读入优化还是T了两个点,3000ms+

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1022
using namespace std;
int n,m,a,b,fa,fb,cnt,q;
int map[N][N],yz[N][N];
char s[N];
inline int read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;
    x=x*f;
}
void init(){
    memset(map,0,sizeof(map));
    memset(yz,0,sizeof(yz));
    cnt=0;fa=0;fb=0;
}
bool check(int x,int y){
    int xx=x-fa,yy=y-fb;
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            if(yz[i][j]==0)continue;
            int rx=xx+i,ry=yy+j;
            if(rx<0||ry<0||rx>n||ry>m||map[rx][ry]==0)return false;
            map[rx][ry]=0;cnt--;
        }
    }
    return true;
}
int main(){
    scanf("%d",&q);
    while(q--){
        init();bool flag=false;
       // scanf("%d%d%d%d",&n,&m,&a,&b);
      //  n=read();m=read();a=read();b=read();
       read(n);read(m);read(a);read(b);
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
             if(s[j]==‘x‘)map[i][j]=1,cnt++;
        }
        for(int i=1;i<=a;i++){
            scanf("%s",s+1);
            for(int j=1;j<=b;j++){
                if(s[j]==‘.‘)continue;
                if(!fa&&!fb)fa=i,fb=j;
                yz[i][j]=1;
            }
        }
        for(register int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(map[i][j]){
                    if(check(i,j)==0){
                        printf("NIE\n");
                        flag=true;break;
                    }
                    if(cnt==0){
                        printf("TAK\n");
                        flag=true;break;
                    }
                }
            }
            if(flag)break;
        }
    }
    return 0;
}

80

看了题解... 想到以前做靶型数独这个题,把未填数的格子放到一个结构体里。

w[i].x,w[i].y分别表示第i个没有填数格子的横纵坐标。

这样的好处是不用遍历整张图,就找到了没填数的格子。

这个题也是这样....

上面的代码不仅遍历了一遍要染色的图,还遍历了整个印章。

最差的情况是10^12...遍历要染色的10^6,印章10^6。

所以把要染色的点和能染色的点抽离出来,放到结构体里。

很好的一个优化,188ms。

ps:某一行后面+***,可以这样理解..

yz[1].x+xx=x,yz[1].y+yy=y.

说明印章的左上角的可以染色的点,要对应

n*m的棋盘要加xx和yy,那么其他可以染色的点也要加这两个数

来对应他们要染色的点。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1009
using namespace std;
int n,m,a,b,cnt_black,yz_black,q;
char s[N];
int map[N][N];
struct Make_Black{
    int x,y;
}gz[N*N],yz[N*N];
bool check(int x,int y){
    int xx=x-yz[1].x,yy=y-yz[1].y;  //***
    for(int i=1;i<=yz_black;i++){
        int nx=yz[i].x+xx,ny=yz[i].y+yy;
        if(nx<0||nx>n||ny<0||ny>m||map[nx][ny]==0)return false;
        map[nx][ny]=false;
    }
    return true;
}
int main(){
    scanf("%d",&q);
    while(q--){
        bool flag=false;
        cnt_black=yz_black=0;
        scanf("%d%d%d%d",&n,&m,&a,&b);
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
             if(s[j]==‘x‘){
                 gz[++cnt_black].x=i;gz[cnt_black].y=j;
                 map[i][j]=true;
             }
        }
        for(int i=1;i<=a;i++){
            scanf("%s",s+1);
            for(int j=1;j<=b;j++)
             if(s[j]==‘x‘)yz[++yz_black].x=i,yz[yz_black].y=j;
        }
        for(int i=1;i<=cnt_black;i++){
            if(map[gz[i].x][gz[i].y])
             if(check(gz[i].x,gz[i].y)==0){
                 flag=true;
                 printf("NIE\n");break;
             }
        }
        if(!flag)printf("TAK\n");
    }
    return 0;
}

时间: 2024-11-09 00:14:46

洛谷P3585 [POI2015]PIE的相关文章

BZOJ 4385 洛谷3594 POI2015 WIL-Wilcze do?y

[题解] 手残写错调了好久QAQ...... 洛谷的数据似乎比较水.. n个正整数!!这很重要 这道题是个类似two pointer的思想,外加一个单调队列维护当前区间内长度为d的子序列中元素之和的最大值. 枚举右端点,如果左端点到右端点的元素和减去区间内长为d的子序列中元素和的最大值,大于给定的P,那么就把左端点向右挪. #include<cstdio> #include<algorithm> #define N 2000010 #define rg register #defi

洛谷P3588 - [POI2015]Pustynia

Portal Description 给定一个长度为\(n(n\leq10^5)\)的正整数序列\(\{a_n\}\),每个数都在\([1,10^9]\)范围内,告诉你其中\(s\)个数,并给出\(m(m\leq2\times10^5)\)条信息.每条信息包含三个数\(L,R,k(Σk\leq 3\times10^5)\)以及\(k\)个正整数\(\{x_k\}\),表示\(a_L..a_R\)中,任意一个\(x\)均比剩下的\(R-L+1-k\)个数大(严格大于,即没有等号).请任意构造出一组

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

洛谷P1466 集合 Subset Sums

洛谷P1466 集合 Subset Sums这题可以看成是背包问题 用空间为 1--n 的物品恰好填充总空间一半的空间 有几种方案 01 背包问题 1.注意因为两个交换一下算同一种方案,所以最终 要 f [ v ] / 2 2.要开 long long 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string&g

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std

洛谷 P3367 并查集模板

#include<cstdio> using namespace std; int n,m,p; int father[2000001]; int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void unionn(int i,int j) { father[j]=i; } int main() { scanf("%d%d",&n,&m); for