GDOI2016模擬8.14電話表

題目
在幻想鄉撥打不同的電話號碼收費標準是完全不同的。博麗神社有一個古老的費用表,來確定撥打電話的花費。

每一個幻想鄉的電話號碼由11 位數字組成。費用表共有N 行,每一行給出一個號碼的前綴範圍和對應收費標準的名稱。對於給出的前綴,如4239-241 ,指所有的前綴爲4239,4240,4241 的電話號碼。要確定撥打每個號碼的收費標準,需要從費用表的第一行開始

依次向下查找,第一個匹配的號碼前綴範圍所對應的收費標準即爲撥打這個號碼的收費標準。如果沒有找到匹配的前綴,那麼認爲此號碼無效。無效號碼的收費標準定義爲’invalid’(不帶引號)。一種收費標準的名稱可以在表上多次出現。

博麗神社的費用表已經很舊了,包含了很多很多的數據,這使得管理變得非常困難。神社的巫女決定將這份費用表修改到更簡單易讀的格式。她希望表內所有號碼前綴都按照字典序排序,並且沒有‘-’符號,同時沒有一個串是另一個串的前綴,且串的總個數最少。’invalid’

和原先不存在的收費標準不能出現在新費用表中。

這題我們可以用trie樹來記錄哪些前綴已被使用,這時候,我們可以用區間查詢來看一下哪些位置沒被找過,找到最近的地方打上標記,並記錄下來(除了incalid的),然後排個序,相鄰且前綴相鄰的屬於同一個名字的合併,剩下的就是不同名字的了。

然後將相鄰的暴力判斷,至少要保留到前幾位才能使他們有區別,並記錄下來,作爲保留的參考,輸出時,能壓縮的儘量壓縮,細節比較多,參考代碼

貼代碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#define N 3500000
#define M 101
#include<cmath>
#include<cstring>
using namespace std;
int f[N][10];
short int bz[N];
int n,maxnlen,sum;
int len[N],b[N],bz1;
long long help[12],a[M][2],ans[N][2],ll,rr;
int ans1[N];
char name[M][M];
void init(){
    static char c[M];
    static char x;
    static int y;
    for (int i=1;i<=n;i++){
        scanf(" %s",&c);
        len[i]=strlen(c);
        maxnlen=max(maxnlen,len[i]);
        a[i][0]=a[i][1]=0;
        for (int j=0;j<len[i];j++)
            (a[i][0]*=10)+=c[j]-'0';
        scanf(" %c",&x);
        scanf(" %s",&c);
        y=strlen(c);
        for (int j=0;j<y;j++)
            (a[i][1]*=10)+=c[j]-'0';
        a[i][1]+=a[i][0]/help[y]*help[y];
        scanf(" %s",&name[i]);
    }
}
bool cmp(int x,int y){
    return a[x][0]<a[y][0]||(a[x][0]==a[y][0]&&a[x][1]>a[y][1]);
}
void pre(){
    static int x;
    for (int i=1;i<=n;i++){
        x=maxnlen-len[i];
        a[i][0]*=help[x],a[i][1]*=help[x];
        a[i][1]+=help[x]-1;
    }
}
void clear(int x){
    for (int i=0;i<10;i++)
        f[x][i]=0;
    bz[x]=0;
}
bool jiao(long long l,long long r,long long x){
    return l<=x&&x<=r;
}
void change(long long l,long long r,int s,int z){
    static long long ss,sss;
    if (bz[s]==2)return;
    if (ll<=l&&r<=rr&&!bz[s]){
        bz[s]=2;
        if (!bz1)return;
        if (ans1[ans1[0]]==bz1&&ans[ans1[0]][1]==l-1)
            ans[ans1[0]][1]=r;
        else{
            ans1[++ans1[0]]=bz1;
            ans[ans1[0]][0]=l,ans[ans1[0]][1]=r;
        }
        return;
    }
    bz[s]=1;
    for (int i=0;i<=9;i++){
        sss=l+help[z]*(i+1)-1;
        ss=l+help[z]*i;
        if (jiao(ll,rr,ss)||jiao(ll,rr,sss)||(ss<=ll&&rr<=sss)){
            if (!f[s][i])
                f[s][i]=++sum,clear(sum);
            change(ss,sss,f[s][i],z-1);
        }
    }
}
bool cmp1(int x,int y){
    return ans[x][0]<ans[y][0];
}
void write(long long x,int y,int bz){
    for (int i=y-1;i>=0;i--)
        printf("%d",x/help[i]%10);
    printf(" %s\n",name[bz]);
}
bool jian(int x){
    if (strlen(name[x])!=7)return 0;
    if (name[x][0]!='i'||name[x][1]!='n'||name[x][2]!='v'||name[x][3]!='a'||name[x][4]!='l'||name[x][5]!='i'||name[x][6]!='d')
        return 0;
    return 1;
}
bool differ(int x,int y){
    static int len;
    if ((len=strlen(name[x]))!=strlen(name[y]))return 1;
    for (int i=0;i<len;i++)
        if (name[x][i]!=name[y][i])return 1;
    return 0;
}
void work(){
    static int x,y;
    static long long xx,yy,z;
    bz1=0;
    for (int i=1;i<=n;i++){
        if (!jian(i))bz1=i;
        else bz1=0;
        ll=a[i][0],rr=a[i][1],change(0,help[maxnlen]-1,1,maxnlen-1);
    }
    for (int i=1;i<=ans1[0];i++)
        b[i]=i,len[i]=maxnlen-1;
    sort(b+1,b+ans1[0]+1,cmp1);
    if (ans1[0])
    b[0]=1;
    else
        b[0]=0;
    for (int i=2;i<=ans1[0];i++)
        if (differ(ans1[b[b[0]]],ans1[b[i]])||ans[b[b[0]]][1]+1!=ans[b[i]][0])
            b[++b[0]]=b[i];
        else
            ans[b[b[0]]][1]=ans[b[i]][1];
    x=b[1];
    while (len[1]&&(ans[x][0]/help[len[1]-1]%10>0||ans[x][0]%help[len[1]-1]>0))len[1]--;
    for (int i=2;i<=b[0];i++){
        y=b[i],x=b[i-1];
        while (len[i-1]&&ans[x][1]%help[len[i-1]])len[i-1]--;
        while (len[i-1]&&ans[y][0]/help[len[i-1]]==ans[x][1]/help[len[i-1]])len[i-1]--;
        len[i]=len[i-1];
    }
    x=0;
    for (int i=1;i<=b[0];i++){
        xx=ans[b[i]][0]/help[len[i]],yy=ans[b[i]][1]/help[len[i]];
        z=1,y=len[i];
        for (;xx*z<=yy;){
            if (!(xx%10)){
                if ((xx/10+1)*z*10-1<=yy&&y+1<maxnlen)
                    xx/=10,z*=10,y++;
                else
                    if ((xx+1)*z-1>yy)xx*=10,z/=10,y--;
                    else
                        x++,xx++;
            }else
                if ((xx+1)*z-1>yy)xx*=10,z/=10,y--;
                else
                    x++,xx++;
        }
    }
    printf("%d\n",x);
    for (int i=1;i<=b[0];i++){
        xx=ans[b[i]][0]/help[len[i]],yy=ans[b[i]][1]/help[len[i]];
        z=1;
        for (;xx*z<=yy;){
            if (!(xx%10)){
                if ((xx/10+1)*z*10-1<=yy&&len[i]+1<maxnlen)
                    xx/=10,z*=10,len[i]++;
                else
                    if ((xx+1)*z-1>yy)xx*=10,z/=10,len[i]--;
                    else
                        write(xx,maxnlen-len[i],ans1[b[i]]),xx++;
            }else
                if ((xx+1)*z-1>yy)xx*=10,z/=10,len[i]--;
                else
                    write(xx,maxnlen-len[i],ans1[b[i]]),xx++;
        }
    }
}
int main(){
    help[0]=1;
    for (int i=1;i<=11;i++)
        help[i]=help[i-1]*10;
    while (scanf("%d",&n)!=-1){
        maxnlen=0;
        init();
        pre();
        sum=1;
        ans1[0]=0;
        clear(1);
        work();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章