A B C D E F G H I J
√ √ √ √ √ √ √ √ √ √
rk:2
A 推箱子
时间限制:1000ms 内存限制:65536kb
题目描述
相信在智能手机没有普及的年代,大家都在电视上玩过推箱子的小游戏,经典的推箱子是一个来自日本的古老游戏,目的是在训练你的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。
现在输入一个nm的矩阵,每个格子都有一个字符,每个字符表示不同的涵义,其中 'P' 代表玩家(有且只有一个),'*' 代表空地,'W' 代表墙,'B' 代表箱子
输入一行指令,A表示玩家向上移动,B表示向下,L表示向左、R表示向右,你需要控制玩家按照指令移动(需要推箱子的时候推动箱子),并在最后输出按照指令移动之后的矩阵。
注意,矩阵的四周都是墙。
玩家的力气有限,不能够推动多个箱子。
输入
首先输入两个整数n和m,表示这是一个nm的矩阵
接下来n行,每行m个字符,表示这个矩阵
接下来一行字符,表示指令
输出
输出按照指令移动之后的矩阵
输入样例
5 5
W*B*W
**WWW
B*B**
***B*
WWPWW
ARLLLARRR
输出样例
W*B*W
B*WWW
***PB
****B
WW*WW
PS
对于非法指令直接忽略就好,比如
数据范围
n,m <= 300,指令长度小于1e6
u1s1这就是个程设题 对于每条指令 如果是非法的continue就好 其他的就交换一下符号就行
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,posx,posy;
char Map[1001][1001];
int main(){
scanf("%d %d",&n,&m);
int i,j;
char cc;
scanf("%c",&cc);
while(cc!='W'&&cc!='B'&&cc!='P'&&cc!='*') scanf("%c",&cc);
Map[0][0]=cc;
int num=1;
int nowx=0;
int nowy=1;
while(num<n*m){
scanf("%c",&cc);
if(cc!='W'&&cc!='B'&&cc!='P'&&cc!='*') continue;
if(cc=='P'){
posx=nowx;
posy=nowy;
}
Map[nowx][nowy]=cc;
nowy++;
if(nowy>=m){
nowy=0;
nowx++;
}
num++;
}
string s;
cin>>s;
int len=s.length();
for(i=0;i<len;i++){
if(s[i]=='A'){
if(posx==0||Map[posx-1][posy]=='W') continue;
if(posx==1&&Map[0][posy]=='B') continue;
if(posx>1&&Map[posx-1][posy]=='B'&&Map[posx-2][posy]!='*') continue;
if(Map[posx-1][posy]=='*'){
Map[posx-1][posy]='P';
Map[posx][posy]='*';
posx--;
}
else if(Map[posx-1][posy]=='B'){
Map[posx-2][posy]='B';
Map[posx-1][posy]='P';
Map[posx][posy]='*';
posx--;
}
}
else if(s[i]=='B'){
if(posx==n-1||Map[posx+1][posy]=='W') continue;
if(posx==n-2&&Map[n-1][posy]=='B') continue;
if(posx<n-2&&Map[posx+1][posy]=='B'&&Map[posx+2][posy]!='*') continue;
if(Map[posx+1][posy]=='*'){
Map[posx+1][posy]='P';
Map[posx][posy]='*';
posx++;
}
else if(Map[posx+1][posy]=='B'){
Map[posx+2][posy]='B';
Map[posx+1][posy]='P';
Map[posx][posy]='*';
posx++;
}
}
else if(s[i]=='L'){
if(posy==0||Map[posx][posy-1]=='W') continue;
if(posy==1&&Map[posx][0]=='B') continue;
if(posy>1&&Map[posx][posy-1]=='B'&&Map[posx][posy-2]!='*') continue;
if(Map[posx][posy-1]=='*'){
Map[posx][posy-1]='P';
Map[posx][posy]='*';
posy--;
}
else if(Map[posx][posy-1]=='B'){
Map[posx][posy-2]='B';
Map[posx][posy-1]='P';
Map[posx][posy]='*';
posy--;
}
}
else if(s[i]=='R'){
if(posy==m-1||Map[posx][posy+1]=='W') continue;
if(posy==m-2&&Map[posx][posy+1]=='B') continue;
if(posy<m-2&&Map[posx][posy+1]=='B'&&Map[posx][posy+2]!='*') continue;
if(Map[posx][posy+1]=='*'){
Map[posx][posy+1]='P';
Map[posx][posy]='*';
posy++;
}
else if(Map[posx][posy+1]=='B'){
Map[posx][posy+2]='B';
Map[posx][posy+1]='P';
Map[posx][posy]='*';
posy++;
}
}
}
for(i=0;i<n;i++){
for(j=0;j<m;j++) printf("%c",Map[i][j]);
printf("\n");
}
return 0;
}
B coming 1CLR
时间限制:200ms 内存限制:3000kb
题目描述
1CLR2021 马上就要截稿了!但是柯柯还在 rush 实验...
为了速速完成论文的 related work,柯柯一下子下载了非常多的相关文献。柯柯开始整理文献,他先按照年份降序排好文献;对于同一年的文献,他再按字典序升序排列。
因为马上就要截稿了,柯柯必须尽早开始阅读文献。你能快点帮他把文献排下序吗?
输入
第一行是一个正整数 n
代表待排序的文献的个数。
接下来 n行,每行一个数字 y 和字符串 c,分别代表该篇文献的发表年份和所属会议名称。
输出
输出 n 行,代表排序后(先按年份降序,同一年的再按字典序升序)的每篇文献。
输入样例
5
2017 1CLR
2016 1CLR
2016 AAA1
2017 AAA1
2017 1CLR
输出样例
2017 1CLR
2017 1CLR
2017 AAA1
2016 1CLR
2016 AAA1
数据范围
n∈[1,3×1e5];y∈[1900,2020].
c∈{ 1CLR, AAA1, CVP2, E33V, ICM1, NIP5 }. ( c 只会是这些字符串之一)
3×1e5的数据nlogn是无法在200ms之内跑完的 加上这道题数据的特殊性:字符串只有六种 年份只有121种,所以可以想到某种O(n)的排序来实现
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int n;
int numm[122],nummm[122][6];
int main(){
scanf("%d",&n);
int i,j,k;
for(i=0;i<n;i++){
int ddd;
char ssss[10];
scanf("%d %s",&ddd,ssss);
if(strcmp(ssss,"1CLR")==0) nummm[ddd-1900][0]++;
else if(strcmp(ssss,"AAA1")==0) nummm[ddd-1900][1]++;
else if(strcmp(ssss,"CVP2")==0) nummm[ddd-1900][2]++;
else if(strcmp(ssss,"ICM1")==0) nummm[ddd-1900][3]++;
else if(strcmp(ssss,"NIP5")==0) nummm[ddd-1900][4]++;
else if(strcmp(ssss,"E33V")==0) nummm[ddd-1900][5]++;
}
for(i=120;i>=0;i--){
for(j=0;j<nummm[i][0];j++) printf("%d 1CLR\n",i+1900);
for(j=0;j<nummm[i][1];j++) printf("%d AAA1\n",i+1900);
for(j=0;j<nummm[i][2];j++) printf("%d CVP2\n",i+1900);
for(j=0;j<nummm[i][5];j++) printf("%d E33V\n",i+1900);
for(j=0;j<nummm[i][3];j++) printf("%d ICM1\n",i+1900);
for(j=0;j<nummm[i][4];j++) printf("%d NIP5\n",i+1900);
}
return 0;
}
C 虫虫爱吃鸡2
时间限制:1000ms 内存限制:65536kb
题目描述
直至今天虫虫还是很爱吃鸡,虽然他仍然没有吃过鸡。
虫虫意识到了自己记忆力不好,所以他想锻炼自己的记忆力。他想在每次换枪的时候,记住当前换枪次数。他又发现只记次数太简单了,所以他想记住当前换枪次数转化为二进制后数目1的个数。
结果实战中,虫虫发现自己计算能力也不行,算不来二进制。你能帮住他在不计算二进制的情况下记住所有的值吗。
输入
一个数n,表示本次对局换枪次数
输出
一行n个整数,表示1~n转化为二进制后数目1的个数
数据范围
1≤n≤1e7
如果你具有丰富的dp经验可以想到这个题显然不是对于每一个n都要重新算的 一定是存在某种递推关系 比如我们对于11100100 就是1100100再加了一个1 并且对于10000000~11111111都是相对于0~1111111在第一位加1 于是递推关系就找出来了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,hnum;
int dp[10000001],bei[100100],beis=1;
int main(){
scanf("%d",&n);
bei[1]=2;
for(int i=2;i<=30;i++) bei[i]=bei[i-1]<<1;
for(int i=1;i<=n;i++){
if(i!=bei[beis]) dp[i]=1+dp[i-hnum];
else{
beis++;
hnum=i;
dp[i]=1;
}
}
for(int i=1;i<=n;i++) printf("%d ",dp[i]);
return 0;
}
D C1-Zexal的过河
时间限制:500ms 内存限制:65536kb
题目描述
Zexal打算借助河中间的石砖过到河对岸去。Zexal从第一块石砖出发,接下来他可以走到第二块石砖或第三块石砖,有时候走的很不爽,甚至可以直接跨过两个石砖,到达第四块石砖,但是不能连续两次这种操作,因为这样消耗体能比较大。现在假设河中含n块石砖,且这些石砖呈直线分布,请你计算出Zexal从第一块石砖出发有多少种安全的过河方法。
输入
输入将由多组测试数据组成,以EOF结尾。
每组数据只有一行,为河中的总石砖数n(0<n≤50)。
输出
对于每组数据,输出一行,为过河的方法数。
很基础的一个递推 到达n这个位置只能通过n-1和n-2即直接通过1/2这种直接到达的方式 但n-3这种不能连续两次到达又怎么办呢 显然n-3的前提是前一次是n-4/n-5通过1/2格子到达 所以即dp[n]=dp[n-1]+dp[n-2]+dp[n-4]+dp[n-5] 直接O(n)递推即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans[100]={1,1,2,4,7};
void init(){
for (int i=5;i<=50;i++){
ans[i]=ans[i-1]+ans[i-2]+ans[i-5]+ans[i-4];
}
}
int main(){
init();
int n;
while(~scanf("%d",&n)) printf("%lld\n",ans[n]);
return 0;
}
E 原神的故事 No.1
时间限制:400ms 内存限制:65536kb
题目描述
安柏一天正在蒙德城外探险,突然发现了一个宝箱,但是只有点燃前面的 n 个火炬才能点亮宝箱下面的魔纹获得宝箱。n个火炬的编号为从 1 到 n 按顺序排列,而这 n 个火炬的能量分别为 ai(1<=i<=n),现在询问 m 次,每次告诉你一个数字 x,安柏能点燃编号从 L 到 R的所有火炬(其中 R-L+1 >= x),请你求出她所能点燃的最大能量。(对于 m 次点燃,每次点燃前所有火炬会全部熄灭)
输入
第一行两个数,表示 n 和 m 。
之后 n 个数,表示 n 个火炬的能量。
之后 m 行每行一个数 x,表示询问的数字。
输出
输出 m 行,为安柏每次所能点燃的最大能量
数据范围
1<=x<=n<=10^4,0<=m<=10^5,|ai|<=10^4
Hint
选一个区间长度>=x的区间,求区间最大和
显然x越大输出结果越小 显然我们可以把所有长度的最大值都求出来 然后结果不递减O(n)扫一下 就可以得到每一个不小于这个长度的结果了(太绕了 不如看代码)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m;
ll a[1001000];
ll sum[1001000];
ll msum[10010];
int main(){
for(int i=0;i<=10000;i++) msum[i]=-999999999;//最大值初始化
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];//前缀和
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
int len=i-j+1;//区间长度
if(sum[i]-sum[j-1]>msum[len]) msum[len]=sum[i]-sum[j-1];//维护最大值
}
}
for(int i=n-1;i>=1;i--){
if(msum[i+1]>msum[i]) msum[i]=msum[i+1];//不递增
}
for(int i=1,x;i<=m;i++){
scanf("%d",&x);
printf("%lld\n",msum[x]);
}
return 0;
}
F 朗基努斯之殇
时间限制:1000ms 内存限制:180000kb
题目描述
百人长因为妄图杀死神,遭到了神的惩罚,被赐予了神器朗基努斯之枪,身体可以无限再生。永世都必须参与战争,在参战-阵亡-复活-再参战的轮回中接受折磨。
而当百人长加入到圣地的阵营当中时,情况发生了些许变化。圣地的研究部门发现,如果能够精准地将百人长一分为二,两块身体都能进行再生,从而变为两个百人长,百人长的武器——朗基努斯之枪同样可以实现这样的过程,圣地将把百人长和朗基努斯之枪一分为二过程称之为“扩张”。
听进来是一件很完美的事情,但可惜的是,朗基努斯之枪在每次“扩张”之后,威力都会下降。若“扩张”前朗基努斯之枪的威力为x,则“扩张”之后的两把新的朗基努斯之枪的威力分别为[ax/b]和x−[ax/b],[x]表示x向下取整,a<b。
圣地希望以此培养一支强大的百人长军团,为了尽可能的让百人长们的战斗力平均一些,圣地的研究部门每次都会选择当前持有最高威力朗基努斯之枪的百人长进行“扩张”。
现在,作为绝对中立势力的魔法师组织——黑塔的一名侦察员,你需要向上级报告,从最初的持有威力为m的朗基努斯之枪的百人长开始,进行k次扩张之后,百人长们手里威力最大的朗基努斯之枪的威力是多少。
输入
第一行,包含一个正整数,为数据的级数T
接下来T行,每行4个整数m,k,a,b,含义见题目描述。
输出
对于每组数据,输出一行,包含一个整数,为百人长们手里威力最大的朗基努斯之枪的威力
数据范围与约束
对于所有数据有∑k<=1e7,m,a,b<=1e8
提示
别想优先队列/手写堆了,过不去的(X)
因为数据较弱 所以我真的用一个假的优先队列7700ms水过了 应该可以hack但我并不想自己hack自己TAT 这里的正解是单调队列 q1和q2一个存放[ax/b]类型的 另一个存放x−[ax/b]类型的 并且对于两个长度l1>l2 l1分出的第一部分如果有机会分的话一定优先于l2分出的第一部分 第二部分同理 所以就可以根据两个单调队列队首的大小来判断是该哪种类型的分。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll m,t,k,a,b;
deque<ll> q1;
deque<ll> q2;
int main(){
scanf("%lld",&t);
for(int i=0;i<t;i++){
scanf("%lld %lld %lld %lld",&m,&k,&a,&b);
ll m1=m*a/b;
ll m2=m-m1;
if(k==0){
printf("%lld\n",m);
continue;
}
else if(k==1){
if(m1>m2)
printf("%lld\n",m1);
else
printf("%lld\n",m2);
continue;
}
k--;
q1.push_back(m1);
q2.push_back(m2);
for(int j=0;j<k;j++){
if(!q2.empty()&&q2.front()>=q1.front()){
ll ans=q2.front();
q2.pop_front();
ll mm1=ans*a/b;
ll mm2=ans-mm1;
q1.push_back(mm1);
q2.push_back(mm2);
}
else if(!q1.empty()&&q1.front()>=q2.front()){
ll ans=q1.front();
q1.pop_front();
ll mm1=ans*a/b;
ll mm2=ans-mm1;
q1.push_back(mm1);
q2.push_back(mm2);
}
}
if(!q1.empty()&&q1.front()>q2.front()) printf("%lld\n",q1.front());
else printf("%lld\n",q2.front());
while(!q1.empty()) q1.pop_front();
while(!q2.empty()) q2.pop_front();
}
return 0;
}
G 给月球贴瓷砖
时间限制:1000ms 内存限制:65536kb
题目描述
你是一个装修公司的CEO,今天你接到了一单生意,让你在月球上贴瓷砖,客户给出的价格不菲,并且愿意承担来往的费用,你很心动,但是客户提出了一些要求,你的任务是给出满足客户要求的方案。
客户主要的要求如下:
只能使用如下的瓷砖
![]()
要布满一个边长为n的矩形区域,除了其中一个用来放置人类月球纪念碑的位置。
ps:n是2的幂
方案有多种,输出其中一种即可
输入
第一行为一个整数,含义如上
接下来两个整数,表示人类月球纪念碑的坐标(从0开始,左上角为坐标原点)
输出
(n*n-1)/3行,每行一个字母,三个坐标,表示一块瓷砖,字母表示颜色,坐标是该瓷砖3个部分的坐标,按照上图标号的顺序输出。
如果不存在可行的方案,请输出None
瓷砖的输出顺序随意。
输入样例
4
1 1
输出样例
y (0,0) (1,0) (0,1)
r (2,0) (3,0) (3,1)
g (0,2) (0,3) (1,3)
b (2,1) (1,2) (2,2)
b (3,2) (2,3) (3,3)
样例解释
如图
![]()
数据范围
n <= 1024
真的一眼就知道是一个递归的问题 如果我们发现要解决的问题是一个正方形里面少一个块问能不能存在一种贴瓷砖的方案 递归的策略就是把一个正方形沿着竖直水平对称轴切割 递归成四个小正方形贴瓷砖的问题 你可能会问另外三个正方形又不少块怎么能说转化了呢 我们可以讨论缺块的位置 然后剩下三个小正方形只需要各自割出一个小块并且让这三个小缺块能连成一个小三角形即可 样例中中间的蓝色砖块就是如此
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,posx,posy;
void work(ll zsx,ll yxx,ll zsy,ll yxy,ll bx,ll by)
{
if(zsx==yxx||zsy==yxy) return;
ll zx=(zsx+yxx)>>1;
ll zy=(zsy+yxy)>>1;
if(bx<=zx&&by<=zy){
printf("b (%lld,%lld) (%lld,%lld) (%lld,%lld)\n",zx,zy-1,zx-1,zy,zx,zy);
work(zsx,zx,zsy,zy,bx,by);
work(zx+1,yxx,zsy,zy,zx+1,zy);
work(zsx,zx,zy+1,yxy,zx,zy+1);
work(zx+1,yxx,zy+1,yxy,zx+1,zy+1);
}
else if(bx<=zx&&by>zy){
printf("r (%lld,%lld) (%lld,%lld) (%lld,%lld)\n",zx-1,zy-1,zx,zy-1,zx,zy);
work(zsx,zx,zsy,zy,zx,zy);
work(zx+1,yxx,zsy,zy,zx+1,zy);
work(zsx,zx,zy+1,yxy,bx,by);
work(zx+1,yxx,zy+1,yxy,zx+1,zy+1);
}
else if(bx>zx&&by<=zy){
printf("g (%lld,%lld) (%lld,%lld) (%lld,%lld)\n",zx-1,zy-1,zx-1,zy,zx,zy);
work(zsx,zx,zsy,zy,zx,zy);
work(zx+1,yxx,zsy,zy,bx,by);
work(zsx,zx,zy+1,yxy,zx,zy+1);
work(zx+1,yxx,zy+1,yxy,zx+1,zy+1);
}
else if(bx>zx&&by>zy){
printf("y (%lld,%lld) (%lld,%lld) (%lld,%lld)\n",zx-1,zy-1,zx,zy-1,zx-1,zy);
work(zsx,zx,zsy,zy,zx,zy);
work(zx+1,yxx,zsy,zy,zx+1,zy);
work(zsx,zx,zy+1,yxy,zx,zy+1);
work(zx+1,yxx,zy+1,yxy,bx,by);
}
}
int main(){
scanf("%lld",&n);
scanf("%lld %lld",&posx,&posy);
posx++;
posy++;
work(1,n,1,n,posx,posy);
return 0;
}
H 妙妙趣排序
时间限制:1000ms 内存限制:65536kb
题面
本题中:
一个即将排好序的序列定义为:将这个序列去除至多一个值后,新序列是严格递增的。
一个过滤器[u,v]定义为:一个序列a经过过滤器[u,v]后,au=min(au,av),av=max(au,av),其他值不变。
妙妙趣排序器由k个过滤器组成,一个序列的妙妙趣排序需要依次经过排序器的k个过滤器。
那么请问,1~n的全排列中,有几个序列经过给定的妙妙趣排序后可以变成即将排好序的序列。
输入
第一行一个正整数t表示数据组数(0<t<100)
接下来t组数据
每组数据第一行两个整数n,k (2≤n≤50,0≤k≤10)
每组数据接下来k行,每行两个整数u,v,表示一个过滤器(1≤u<v≤n)
输出
每组数据输出一行,一个整数
输入样例
4
4 0
4 1
1 2
4 3
1 2
2 3
1 2
4 6
1 2
2 3
1 2
3 4
2 3
1 2
输出样例
暴力找就行了 没什么意思(x)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll num=1,ans;
int l[100],r[100];
int a[3000][100];
void cas(int n){
for(int i=0;i<n;i++){
int insnum=a[0][i];
for(int j=0;j<n;j++){
if(j==i||j==i-1) continue;
a[num][j]=insnum;
for(int l=0,m=0;l<n&&m<n;l++,m++){
if(m==j) m++;
if(l==i) l++;
a[num][m]=a[0][l];
}
num++;
}
}
}
void f(int yy,int yyy,int flag){
if(yyy<0){
ans++;
return;
}
if(a[yy][l[yyy]-1]>a[yy][r[yyy]-1]) return;
int aa=a[yy][l[yyy]-1];
int bb=a[yy][r[yyy]-1];
f(yy,yyy-1,0);
a[yy][r[yyy]-1]=aa;
a[yy][l[yyy]-1]=bb;
f(yy,yyy-1,1);
a[yy][r[yyy]-1]=bb;
a[yy][l[yyy]-1]=aa;
}
int main(){
int t,n,k;
scanf("%d",&t);
for(int i=0;i<t;i++){
num=1;
ans=0;
memset(a,0,sizeof(a));
scanf("%d%d",&n,&k);
for(int j=0;j<n;j++) a[0][j]=j+1;
cas(n);
for(int j=0;j<k;j++) scanf("%d %d",&l[j],&r[j]);
for(int kk=0;kk<num;kk++) f(kk,k-1,0);
printf("%lld\n",ans);
}
return 0;
}
I 看看是不是三角形
时间限制:1000ms 内存限制:65536kb
题面
n根木棍,编号为1~n,已知每一根木棍的长度。
m次查询,每次查询区间[L,R]内是否存在三根木棍可以组成三角形。
输入
第一行两个正整数n,m(1≤n,m≤1e5)
第二行n个正整数,表示木棍的长度ai(1≤ai≤109)
接下来m行,每行两个正整数L,R,表示查询的区间(1≤L≤R≤n)
输出
如果存在三根木棍可以组成三角形,输出Yes,否则输出No
其实可以发现当数列个数到达一定长度是必定存在的 因为不存在的情况最顽强的情况是 1 2 3 5 8...是一个斐波那契数列的形式 发现50多项就爆了int 所以大于54的情况我们可以看成一定存在 少于这些的情况 排一个序O(r-l)扫一下就可以了 别忘了少于3的情况不存在
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,posx,posy,l,r;
ll a[200100],b[200100];
int main(){
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0;i<m;i++){
int flag=0;
scanf("%lld %lld",&l,&r);
if(r-l>=46){
printf("Yes\n");
continue;
}
else if(r-l<2){
printf("No\n");
continue;
}
for(int k=l;k<=r;k++) b[k-l]=a[k];
sort(b,b+r-l+1);
for(int k=0;k<=r-l-2;k++){
if(b[k]+b[k+1]>b[k+2]){
flag=1;
break;
}
}
if(flag==1) puts("Yes");
else puts("No");
}
return 0;
}
J 数码管检测
时间限制:500ms 内存限制:65536kb
题目描述
Kazamori 在《电子设计基础训练》课上学习了七段数码管的使用方法。数码管能够方便的显示出 0 到 9 的数字。以下是每个数字的表示形式。
![]()
假设 LED 手表的屏幕由四个七段数码管(表示小时和分钟)和中间两个短管(表示冒号 : ) 组成。
手表上显示的时间可以抽象为 7行长度为 21 的字符串。每个七段数码管用 7×4 ( 7 行 4 列)的字符串表示,数码管与数码管或冒号之间用一列 . 隔开。每个数码管由两个字符表示,冒号上下各用一个字符表示。X 代表这段数码管是亮的,. 代表其他情况(这段数码管灭或者非数码管位置)。以下是 20:36 的表示
.XX...XX.....XX...XX.
...X.X..X......X.X...
...X.X..X.X....X.X...
.XX..........XX...XX.
X....X..X.X....X.X..X
X....X..X......X.X..X
.XX...XX.....XX...XX.
其中,第 1−4 列表示 2,第 6−9 列表示 0 ,第 11 列表示冒号 ,第 13−16 列表示 3 ,第 18−21 列表示 6。
现在手表出了故障,有些数码管不能正常工作,可能表现为永远亮或永远灭。不会存在非数码管位置亮的情况。
给你连续 n分钟的手表的显示情况,请编写一个程序判断数码管的状态。
输入
第一行一个正整数 n( n≤100),含义如上所述。
接下来 7n行,每行一个长度为 21的字符串,表示手表的显示情况。每分钟之间以一个空行分隔。
输出
如果给出的情况是不可能发生的,输出 impossible 。
否则按以下规则输出 7行长度为 21 的字符串。 如果对应位置的数码管正常工作,输出 W ;对应位置的数码管永远灭,输出 0 ; 对应位置的数码管永远亮,输出 1 ;对应位置的状态不能确定,输出 ? 。对于非数码管的位置,输出 . 。
输入样例
3
......XX.....XX...XX.
.....X..X...X..X....X
.....X..X.X.X..X....X
.............XX...XX.
.....X..X......X.X..X
.....X..X......X.X..X
......XX.....XX...XX.
......XX.....XX...XX.
.....X..X...X..X....X
.....X..X.X.X..X....X
.............XX...XX.
.....X..X......X.X..X
.....X..X......X.X..X
......XX.....XX...XX.
.............XX...XX.
........X...X..X....X
........X.X.X..X....X
.............XX......
........X...X..X.X..X
........X...X..X.X..X
......XX.....XX...XX.
输出样例
.??...WW.....??...??.
?..?.W..?...?..1.0..?
?..?.W..?.?.?..1.0..?
.??...??.....11...WW.
?..?.W..?.0.W..?.1..?
?..?.W..?...W..?.1..?
.??...11.....??...??.
输入样例2
2
......XX.....XX...XX.
...X....X...X..X.X..X
...X....X.X.X..X.X..X
......XX..........XX.
...X.X....X.X..X.X..X
...X.X......X..X.X..X
......XX.....XX...XX.
......XX.....XX......
...X....X...X..X.....
...X....X.X.X..X.....
......XX.............
...X.X....X.X..X.....
...X.X......X..X.....
......XX.....XX......
输出样例2
impossible
HINT
样例一中可能的情况有 (0:58,0:59,1:00) (10:58,10:59,11:00) (20:58,20:59,21:00)
程设恶心题 谁爱做谁做吧
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct DigitalWatch {
string Crystal[7];//7行水晶管
DigitalWatch(string a = "", string b = "", string c = "", string d = "", string e = "", string f = "", string g = "") {
Crystal[0] = a, Crystal[1] = b, Crystal[2] = c, Crystal[3] = d, Crystal[4] = e, Crystal[5] = f, Crystal[6] = g;
}
DigitalWatch operator + (const DigitalWatch& o) const {
DigitalWatch ret;
for (int i = 0; i < 7; ++i)
ret.Crystal[i] = Crystal[i] + o.Crystal[i];
return ret;
}
bool operator == (const DigitalWatch& o) const {
for (int i = 0; i < 7; ++i)
if (Crystal[i] != o.Crystal[i])return false;
return true;
}
DigitalWatch piece(int from, int _size) {
DigitalWatch ret;
for (int i = 0; i < 7; ++i)
ret.Crystal[i] = Crystal[i].substr(from, _size);
return ret;
}
void read() {
for (int i = 0; i < 7; ++i)
cin >> Crystal[i];
}
void print() {
for (int i = 0; i < 7; ++i)cout << Crystal[i] << endl;
}
};
DigitalWatch Number[12];//10个数字的液晶管碎片 下标10对应的是空的小时位
DigitalWatch Colon, Space;//冒号和空格的液晶管碎片
//于是乎,这7行21列的形式就是 数字+空格+数字+空格+冒号+空格+数字+空格+数字
inline void buildPiece() {
Number[0] = DigitalWatch(
".XX.",
"X..X",
"X..X",
"....",
"X..X",
"X..X",
".XX."
);
Number[1] = DigitalWatch(
"....",
"...X",
"...X",
"....",
"...X",
"...X",
"...."
);
Number[2] = DigitalWatch(
".XX.",
"...X",
"...X",
".XX.",
"X...",
"X...",
".XX."
);
Number[3] = DigitalWatch(
".XX.",
"...X",
"...X",
".XX.",
"...X",
"...X",
".XX."
);
Number[4] = DigitalWatch(
"....",
"X..X",
"X..X",
".XX.",
"...X",
"...X",
"...."
);
Number[5] = DigitalWatch(
".XX.",
"X...",
"X...",
".XX.",
"...X",
"...X",
".XX."
);
Number[6] = DigitalWatch(
".XX.",
"X...",
"X...",
".XX.",
"X..X",
"X..X",
".XX."
);
Number[7] = DigitalWatch(
".XX.",
"...X",
"...X",
"....",
"...X",
"...X",
"...."
);
Number[8] = DigitalWatch(
".XX.",
"X..X",
"X..X",
".XX.",
"X..X",
"X..X",
".XX."
);
Number[9] = DigitalWatch(
".XX.",
"X..X",
"X..X",
".XX.",
"...X",
"...X",
".XX."
);
Number[10] = DigitalWatch(
"....",
"....",
"....",
"....",
"....",
"....",
"...."
);
Colon = DigitalWatch(
".",
".",
"X",
".",
"X",
".",
"."
);
Space = DigitalWatch(
".",
".",
".",
".",
".",
".",
"."
);
}
int n;
DigitalWatch a[110];
DigitalWatch timetable[1550];
inline void getWatchFormTime(int timeline, DigitalWatch &s) {//0到1439
timeline %= 1440;
int h = timeline / 60, m = timeline % 60;
int t1 = h / 10 ? h / 10 : 10, t2 = h % 10, t3 = m / 10, t4 = m % 10;
s = Number[t1] + Space + Number[t2] + Space + Colon + Space + Number[t3] + Space + Number[t4];
}
inline void initTimeTable() {
for(int i = 0; i <= 1540; ++i)
getWatchFormTime(i, timetable[i]);
}
enum result {unknown, notdigital, normal, breakdown_1, breakdown_0};
struct AnswerPack {
result ans[8][22];
AnswerPack() {
memset(ans, 0, sizeof(ans));
ans[0][0] = ans[0][3] = ans[0][4] =
ans[0][5] = ans[0][8] = ans[0][9] =
ans[0][10] = ans[0][11] = ans[0][12] =
ans[0][15] = ans[0][16] = ans[0][17] = ans[0][20] = notdigital;
ans[1][1] = ans[1][2] = ans[1][4] =
ans[1][6] = ans[1][7] = ans[1][9] =
ans[1][10] = ans[1][11] = ans[1][13] =
ans[1][14] = ans[1][16] = ans[1][18] = ans[1][19] = notdigital;
ans[2][1] = ans[2][2] = ans[2][4] =
ans[2][6] = ans[2][7] = ans[2][9] =
ans[2][11] = ans[2][13] = ans[2][14] =
ans[2][16] = ans[2][18] = ans[2][19] = notdigital;
ans[3][0] = ans[3][3] = ans[3][4] =
ans[3][5] = ans[3][8] = ans[3][9] =
ans[3][10] = ans[3][11] = ans[3][12] =
ans[3][15] = ans[3][16] = ans[3][17] = ans[3][20] = notdigital;
ans[4][1] = ans[4][2] = ans[4][4] =
ans[4][6] = ans[4][7] = ans[4][9] =
ans[4][11] = ans[4][13] = ans[4][14] =
ans[4][16] = ans[4][18] = ans[4][19] = notdigital;
ans[5][1] = ans[5][2] = ans[5][4] =
ans[5][6] = ans[5][7] = ans[5][9] =
ans[5][10] = ans[5][11] = ans[5][13] =
ans[5][14] = ans[5][16] = ans[5][18] = ans[5][19] = notdigital;
ans[6][0] = ans[6][3] = ans[6][4] =
ans[6][5] = ans[6][8] = ans[6][9] =
ans[6][10] = ans[6][11] = ans[6][12] =
ans[6][15] = ans[6][16] = ans[6][17] = ans[6][20] = notdigital;
}
//多种可能结果进行对比,如果出现不一样的可能性,一律定为未知
AnswerPack operator ^ (const AnswerPack & o) const {
AnswerPack ret = AnswerPack();
for(int i = 0; i < 7; ++i)
for(int j = 0; j < 21; ++j)
ret.ans[i][j] = (this->ans[i][j] == o.ans[i][j]) ? this->ans[i][j] : unknown;
return ret;
}
inline void print() {
for(int i = 0; i < 7; ++i) {
for(int j = 0; j < 21; ++j) {
switch (ans[i][j]) {
case unknown:putchar('?'); break;
case notdigital:putchar('.'); break;
case normal:putchar('W'); break;
case breakdown_0:putchar('0'); break;
case breakdown_1:putchar('1'); break;
default:break;
}
}
putchar('\n');
}
}
};
AnswerPack possible[1450];
int legal_size;
//记录所有的可能性的种类
bool breakdown[8][22];//对应晶体管是否出现故障
bool occur[2][8][22];//亮和灭的记录,故障管如果不是永远亮或者灭的那就非法
inline void buildOccur() {
for(int k = 0; k < n; ++k) {
for(int i = 0; i < 7; ++i) {
for(int j = 0; j < 21; ++j) {
int num = a[k].Crystal[i][j] == 'X';
occur[num][i][j] = true;
}
}
}
}
inline bool parse(int s) {//从timetable的s开始进行对比
//memset(occur, 0, sizeof(occur));
memset(breakdown, 0, sizeof(breakdown));
for(int k = 0; k < n; ++k) {
for(int i = 0; i < 7; ++i) {
for(int j = 0; j < 21; ++j) {
if(timetable[k + s].Crystal[i][j] != a[k].Crystal[i][j]) {
breakdown[i][j] = true;
if(occur[0][i][j] && occur[1][i][j] && breakdown[i][j])
return false;
}
}
}
}
return true;
}
AnswerPack get_ans() {
AnswerPack ret = AnswerPack();
for(int i = 0; i < 7; ++i) {
for(int j = 0; j < 21; ++j) {
if(ret.ans[i][j] == notdigital)continue;
if(breakdown[i][j])
ret.ans[i][j] = occur[0][i][j] ? breakdown_0 : breakdown_1;
else if (occur[0][i][j] == occur[1][i][j])
ret.ans[i][j] = normal;
else ret.ans[i][j] = unknown;
}
}
return ret;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
buildPiece();
initTimeTable();
cin >> n;
for(int i = 0; i < n; ++i)
a[i].read();
buildOccur();
for(int i = 0; i < 1440; ++i)
if(parse(i))
possible[++legal_size] = get_ans();
if(legal_size == 0)puts("impossible");
else {
for(int i = 2; i <= legal_size; ++i)
possible[1] = possible[1] ^ possible[i];
possible[1].print();
}
}