【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% 的隨機資料。
思路
首先,如果範圍小,可以暴力過。
如果範圍大:
- 對於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
類似於上面的判斷 - 對於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();
}