1. 程式人生 > >【JZOJ B組】【NOIP2013模擬】終極武器

【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();
}