【JZOJ B组】【NOIP2013模拟】终极武器

Description

  经过一番周折,精英队伍的队员们终于来到了关押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]

Output

每行一个等价类,各行之内都按照数字从小到大排序,数字中间没有空格,行与行之间按照等价类中最小的数字从小到大排序。具体格式参考样例。

Sample Input

样例输入1

1 1

1 566

样例输入2

1 2

30 75

Sample Output

样例输出1

123456

789

样例输出2

12

345

6

7

89

样例解释:

第一个样例中,只允许修改个位。对于1~559这些数,个位无论如何修改都在波段内。对于560~566这些数,个位修改为大于等于7的数字时(例如562的2修改为8),就不在波段内了。因此1~6和7~9属于不同的等价类。

第二个样例每一位上都可以修改。修改方法与上面一个样例类似。

Data Constraint

对于25% 的数据,1<=n<=50,1<=ai<=bi<=6000。

对于另25% 的数据,n=1。

对于另30% 的数据,k=1。

对于100% 的数据,1<=n<=10000,1<=k<=19,1<=ai<=bi<=10^18。

在所有的数据中,均匀分布着25% 的随机数据。

思路

首先,如果范围小,可以暴力过。

如果范围大:

  1. 对于y[i]-x[i]<100000
    暴力枚举一个j(0<=j<=y[i]-x[i])
    设t=x[i]+j
    如果现在是判断a,b是否等类
    从后往前将t每一位截出来
    如果t==a,那么使p=w-a*i+b*i(i就是当前从后往前截到哪一位)
    然后再所有x[i],y[i]的区间里跑,如果w在一个区间内,就是等类的
    设t=y[i]-j
    类似于上面的判断
  2. 对于y[i]-x[i]>100000
    枚举一个j(0<=j<=10000)
    向上面一样判断一下

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=12,maxn=10077;
int n,k,f[20][N],a[N][N+3];
long long x[maxn],y[maxn],s;
bool vis[N];
bool pd(int a,int b)
{
    for(int i=1; i<=k; i++) if(f[i][a]!=f[i][b]) return 0;
    return 1;
}
void doit(long long x)
{
    long long t=x,len=1;
    while(t)
    {
        if(len>k) break;
        f[len][t%10]++; t=t/10; len++;
    }
}
void baoli()
{
    for(int i=1; i<=n; i++) for(long long j=x[i]; j<=y[i]; j++) doit(j);
    for(int i=1; i<=9; i++) if(!vis[i])
    {
        printf("%d",i);
        for(long long j=i+1; j<=9; j++) if(pd(i,j))
        {
            vis[j]=1;
            printf("%d",j);
        }
        printf("\n");
    }
}
bool is_in(long long p)
{
    for(int i=1; i<=n; i++) if(x[i]<=p&&p<=y[i]) return 1;
    return 0;
}
bool check(long long x,int a,int b)
{
    long long t=x,p=1;
    int len=1;
    while(t)
    {
        if(len>k) break;
        if(t%10==a) if(!is_in(x-a*p+b*p)) return 0;
        t=t/10; p=p*10; len++;
    }
    return 1;
}
bool pd1(int a,int b)
{
    for(int i=1; i<=n; i++)
    {
        if(y[i]-x[i]>100000)
        {
            for(int j=0; j<10000; j++)
                if((check(x[i]+j,a,b)&&check(x[i]+j,b,a)&&check(y[i]-j,a,b)&&check(y[i]-j,b,a))==0) return 0;
        }
        else 
        {
            for(int j=0; j<=y[i]-x[i]; j++)
            {
                if(j<=10||(x[i]+j)%10==0)
                {
                    if((check(x[i]+j,a,b)&&check(x[i]+j,b,a)&&check(y[i]-j,a,b)&&check(y[i]-j,b,a))==0) return 0;
                }
                else 
                {
                    long long w=x[i]+j;
                    if(w%10==a)
                    {
                        if(is_in(w-a+b)==0) return 0;
                    }
                    else 
                        if(w%10==b)
                        {
                            if(is_in(w+a-b)==0) return 0;
                        }
                }
            }
        }
    }
}
void dfs(int x,int y)
{
    if(y>9) return;
    if(pd1(x,y)) a[x][++a[x][0]]=y,vis[y]=1;
    dfs(x,y+1);
}
void solve()
{
    for(int i=1; i<=9; i++) if(!vis[i])
    {
        a[i][++a[i][0]]=i; vis[i]=1; dfs(i,i+1);
    }
    for(int i=1; i<=9; i++) 
    {
        for(int j=1; j<=a[i][0]; j++) printf("%d",a[i][j]);
        printf("\n");
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; i++) scanf("%lld%lld",&x[i],&y[i]),s+=y[i]-x[i];
    if(s<10000000) baoli(); else solve();
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/81045300