题目描述
经过一番周折,精英队伍的队员们终于来到了关押applepi的牢狱面前。心中神一般的领袖applepi就在眼前,队员们都不由自主地跪烂膝盖……不过令他们沮丧的是,牢狱的大锁没有钥匙孔,黑魔法师Vani根本就没有指望它再被打开。幸好队员们携带了新研制的终极武器——k型氙激光器(Xenon Laser - k,代号XLk),可以用来破拆这把锁。不过作为一道终极武器,它的启用规则异常严格。
Xenon Laser - k上共有N个波段能够发射激光,每个波段可以用一个闭区间[ai,bi]来表示,其中ai,bi为正整数,b[i-1]<ai≤bi。对于两个数字p和q,如果对于这N个波段内的任意一个整数num,把它在十进制表示下的后k位中某一位上的p换成q(或者q换成p),都满足得到的整数仍然在这N个波段内,那么称在该激光器中,数字p和q是k等价的。我们称两两之间k等价的数字组成一个k等价类。
激光器附带了9个发射匣,代表1~9这9个数字。只有把同一个等价类的数字对应的发射匣安置在一排上,Xenon Laser - k才能够启动。给定个波段,现在就请你求出1~9这9个数字分成了哪些等价类,并且每行输出一个等价类。
本题描述比较抽象,请参考样例解释。
Input
第一行两个整数N,k。
接下来N行每行两个整数ai,bi。ai,bi为正整数,满足b[i-1]
分析
以下部分源自他人题解
读入所有区间之后,转化为前闭后开形式即 [L,R),存入数组……然后我们拿出其中的一个区间来考虑。。。
单独对于这个区间,我们考虑第 k 位上的数字变化。如果我们知道比第 k 位低的位上都是都是什么数字的话,显然可以很容易地判断出这一位上的数字 1~9 可以分成哪两组等价类……
比如区间[2012,6278),考虑十位。如果规定各位数字是 0,那么[2020,6280)中的数在区间内,剩下的在区间外,即十位上[2,8)是一个等价类,其余数字是另一个。如果规定个位数字是 2,那么十位上是[1,8),如果个位数字是 8,那么十位上是[1,7)。
可以发现最初第 k 位上的数字的其中一组是[L/10^k %10 +1, R/10^k %10 +1),当后面的位经过 L%10^k 这个数的时候区间左端减一,经过 R%10^k 这个数的时候区间右端减一。
因此我们可以依次处理每一位,对于每一位上,把读入的 n 个区间中,所有这样引起该位数字区间变化的数值记录下来,排序离散化之后再依次处理。可以发现引起变化的位置只可能是这 n 个区间的左右端点,并且变化规律就是上面一段所说的。
大概梳理一下整个算法过程:
初始化:建一个 9*9 的完全图的邻接矩阵。
特殊处理个位情况。
主要环节:1.枚举每一位,设当前枚举到第 k 位。
2.按照上面所述的方法计算引起变化的位置,排序,离散化,离散后的每个位置开一个 1*9的数组记录哪些数字在数字区间内,哪些在外面。
3.首先令后 k-1 位都是 0,计算各个数字区间(1*9 的数组)的初始值。
4.依次循环每个变化位置,对应的 1*9 的数组里进行加减。
5.每次变化后把对应的 1*9 数组的信息反映到 9*9 的矩阵里,不同集合内的边断掉。
输出答案。
以下是我的细节部分:
首先照着上面算是没错的,然后我搞了一个判别值(估计是哈希的作用):
对于第w位,判别值为:
nubmermod10w−1
n
u
b
m
e
r
mod
10
w
−
1
通过对这个值的排序达到离散化的效果
然后我用了一个叫array的结构体储存对于第二步的1*9数组和离散化数组的开头结尾
然后一波排序,离散化,修改值,就可以用dfs输出了
貌似我和JZ的yangle大佬撞思路了,如有雷同,纯属偶然
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
typedef long long ll;
const int N=10001;
using namespace std;
bool d[10][10],f[4*N][10],v[N];
ll l[N],r[N],pow[20],pc[2];
int n,k,cnt;
struct ptinarray {
ll num,bck;
bool flg;
void read(ll n1,ll b1,bool f1) {
num=n1;bck=b1;flg=f1;
}
}p[4*N];
int pcnt;
bool Cmp(ptinarray a,ptinarray b) {return a.bck<b.bck;}
struct array {
int h,t;
bool f[10];
void sortpt() {
sort(p+h+1,p+t+1,Cmp);
}
void Paint_line(int l,int r) {
int i;
rep(i,l,r) f[i]=1;
}
}a[4*N];
void Init() {
int i,j;
scanf("%d%d",&n,&k);
pow[0]=1;
rep(i,1,19) pow[i]=pow[i-1]*10;
memset(d,1,sizeof d);
rep(i,1,n) {
scanf("%lld%lld",&l[i],&r[i]);
if (r[i]==pow[18]) {
r[i]--;
rep(j,2,9) d[1][j]=d[j][1]=0;
}
if (k==19)
k--;
}
}
void Update(bool *c) {
int ca[10],cb[10],i,j;
memset(ca,0,sizeof ca);memset(cb,0,sizeof cb);
rep(i,1,9) if (c[i]) ca[++ca[0]]=i; else cb[++cb[0]]=i;
rep(i,1,ca[0]) rep(j,1,cb[0]) d[ca[i]][cb[j]]=d[cb[j]][ca[i]]=0;
}
void Unit_push(ll x,ll l,ll r) {
int i;
if (pc[cnt%2]!=x) pc[++cnt%2]=x;
rep(i,l,r) f[cnt][i]=1;
}
void Unit() {
int i;
cnt=1;
rep(i,1,n) {
ll dl=l[i]/pow[1],dr=r[i]/pow[1],l1=l[i]%pow[1],r1=r[i]%pow[1];
if (dl==dr) Unit_push(dl,l1,r1);
else {
if (l1>1) Unit_push(dl,l1,9);
if (r1&&r1<9) Unit_push(dr,1,r1);
}
}
rep(i,1,cnt) Update(f[i]);
}
void Digit_push(ll x,ll l,ll r,int w) {
int i;
if (pc[cnt%2]!=x) {
a[cnt].t=pcnt;
pc[++cnt%2]=x;
a[cnt].h=pcnt;
}
a[cnt].Paint_line(l/pow[w-1]+1,(r-1)/pow[w-1]);
if (l!=pow[w]) p[++pcnt].read(l/pow[w-1],l%pow[w-1],0);
if (r!=pow[w]) p[++pcnt].read(r/pow[w-1],r%pow[w-1],1);
}
void Digit(int w) {
int i,j;
cnt=1;pcnt=0;pc[0]=pc[1]=0;
rep(i,1,n) {
ll dl=l[i]/pow[w],dr=r[i]/pow[w],l1=l[i]%pow[w],r1=r[i]%pow[w];
r1++;
if (dl==dr) Digit_push(dl,l1,r1,w);
else {
if (l1>1) Digit_push(dl,l1,pow[w],w);
if (r1&&r1<pow[w]-1) Digit_push(dr,pow[w-1],r1,w);
}
}
a[cnt].t=pcnt;
rep(i,1,cnt) {
a[i].sortpt();
rep(j,a[i].h+1,a[i].t) {
a[i].f[p[j].num]=!p[j].flg;
if (p[j].bck!=p[j+1].bck) Update(a[i].f);
}
}
}
void Dfs(int u) {
int i;
v[u]=1;
printf("%d",u);
rep(i,1,9)
if (d[u][i]&&!v[i]) Dfs(i);
}
void Solve() {
int i;
Unit();
rep(i,2,k) {
memset(p,0,sizeof p);memset(a,0,sizeof a);
Digit(i);
}
rep(i,1,9)
if (!v[i]) {
Dfs(i);
printf("\n");
}
}
int main() {
Init();
Solve();
}