这道题老实说略奇怪的样子,UVALIVE上过的人少得异常,然后我在LIVE上过的代码放在POJ上同样的题就TLE……不管了这么多了……
题意是说,给出很多个不相交的连续正整数区间,总体记为集合S。定义{1,2...9}上的一种等价关系~,其中对于两个数P和Q,若对于S中的每个数N,将N十进制表示中的一个P换成Q或是一个Q换成P,新的数仍在S中,则P~Q。现在讲1~9按这种等价关系划分成若干个等价类。
这题最初看上去完全没思路,后来想到的方法是直接暴力枚举10^18中每个十进制数位,对于第T位上的P,其在S中所有*P*(P在从右到左的第T位)形式的数,将其中的P取出,所得到的新数也可以构成若干段不相交的连续正整数区间。那么我们有如果P~Q,那么对于每个T,两个数对应的区间应该完全相同;否则,只要有不同,我们就可以找到一个数N,使得N中的P换为Q或Q换为P后,新数不在要求区间内。
这样,直接暴力枚举所有的T,算出每个数P对应的区间,两两比较即可。另外这题在写整数区间并的时候要注意,如果是存区间的两个端点,对于[a,b]和[b+1,c],取并时要化为一个区间。因为这个还错了好多次……
附上这个POJ过不了的代码……
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
bool c[15][15],ap[15];
struct inte
{
ll x,y;
inte(ll x=0,ll y=0):x(x),y(y){}
void read(){scanf("%lld %lld",&x,&y);}
};
bool operator <(inte a,inte b){return a.y+1<b.x;}
bool operator ==(inte a,inte b){return !(a<b||b<a);}
void add(set<inte> &s,inte a)
{
if(a.x>a.y) return;
set<inte>::iterator ite=s.find(a);
while(ite!=s.end())
{
a=inte(min(ite->x,a.x),max(ite->y,a.y));
s.erase(*ite);
ite=s.find(a);
}
s.insert(a);
}
int n;
inte a[10005];
ll cf[19]={1};
set<inte> s[105];
set<inte>::iterator it1,it2;
int main()
{
int i,j,k,l,I=0;
for(i=1;i<19;i++) cf[i]=cf[i-1]*10;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++) a[i].read();
sort(a,a+n);
memset(c,true,sizeof(c));
memset(ap,false,sizeof(ap));
for(i=0;i<=18;i++)
{
if(cf[i]>a[n-1].y) break;
if(i==18) {for(j=2;j<=9;j++) c[1][j]=c[j][1]=0;break;}
for(j=1;j<10;j++)
{
s[j].clear();
for(k=0;k<n;k++)
{
ll t1=a[k].x,t2=a[k].y;
ll tt=t1/cf[i]%10;
if(tt<j) t1=t1/cf[i+1]*cf[i];
else if(tt>j) t1=(t1/cf[i+1]+1)*cf[i];
else t1=t1/cf[i+1]*cf[i]+t1%cf[i];
tt=t2/cf[i]%10;
if(t2/cf[i+1]==0&&tt<j) continue;
if(tt<j) t2=(t2/cf[i+1]-1)*cf[i]+cf[i]-1;
else if(tt>j) t2=(t2/cf[i+1])*cf[i]+cf[i]-1;
else t2=(t2/cf[i+1])*cf[i]+t2%cf[i];
if(t1<=t2) {ap[j]=1;add(s[j],inte(t1,t2));}
}
}
for(j=1;j<10;j++)
for(k=j+1;k<10;k++)
{
if(c[j][k]==0) continue;
if(int(s[j].size()-s[k].size())!=0) {c[j][k]=c[k][j]=0;continue;}
it1=s[j].begin();it2=s[k].begin();
while(it1!=s[j].end()&&it2!=s[k].end())
{
if(it1->x!=it2->x||it1->y!=it2->y) {c[j][k]=c[k][j]=0;break;}
++it1;++it2;
}
}
}
//for(i=1;i<10;i++,cout<<endl) for(j=1;j<10;j++) cout<<c[i][j]<<" ";
if(I++) printf("\n");
int vis[10]={0};
for(i=1;i<10;i++)
{
if(vis[i]) continue;
vis[i]=1;
printf("%d",i);
for(j=i+1;j<10;j++) if(vis[j]==0&&c[i][j]) {printf("%d",j);vis[j]=1;}
printf("\n");
}
}
return 0;
}