Codeforces 1424M - Ancient Language (拓撲排序)
阿新 • • 發佈:2021-01-20
Bubble Cup 13 - Finals [Online Mirror, unrated, Div. 2] M. Ancient Language
題意
給定一個共有\(n\)頁的字典,每一頁有\(k\)個單詞
已知這本字典使用的古老語言的字母是英文字母的子集,不一定\(26\)個英文字母都被使用到
問你是否存在一種字典序滿足這本字典內單詞原來的排列順序
存在的話只需要輸出任意一種即可,不存在輸出IMPOSSIBLE
限制
\(1\le n,k\le 1000\)
\(0\le p_i\lt 1000\)
思路
將給定的所有單詞按照題意進行排序,頁碼小的放前,頁碼相同的按照輸入順序排序
然後考慮所有的相鄰單詞,這裡以\(i,j\)
如果\(i,j\)兩個單詞相同,不考慮
如果\(i,j\)兩個單詞不同,且\(i\)是\(j\)的字首,不考慮
如果\(i,j\)兩個單詞不同,且\(j\)是\(i\)的字首,明顯這樣不可能有滿足的字典序,輸出IMPOSSIBLE
如果\(i,j\)兩個單詞不同,且不滿足上述兩種條件,則只看出現不同字母時下標最小的那個位置\(k\)
令\(a\)表示第\(i\)個單詞下標為\(k\)的字母,令\(b\)表示第\(j\)個單詞下標為\(k\)的字母
可以發現,\(a\)的字典序應該是小於\(b\)的,所以將\(26\)個英文字母看作點,將\(a\rightarrow b\)
明顯的,只有當最後產生的圖是一個DAG時才存在一個解,所以我們每次找入度為\(0\)的點加入答案中即可,直接拓撲排序搜尋即可
程式
(826ms/2000ms)
// StelaYuri //#include<ext/pb_ds/assoc_container.hpp> //#include<ext/pb_ds/hash_policy.hpp> #include<bits/stdc++.h> #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define multiCase int T;cin>>T;for(int t=1;t<=T;t++) #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i<(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define perr(i,a,b) for(int i=(a);i>(b);i--) #define pb push_back #define eb emplace_back #define mst(a,b) memset(a,b,sizeof(a)) using namespace std; //using namespace __gnu_pbds; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int INF=0x3f3f3f3f; const ll LINF=0x3f3f3f3f3f3f3f3f; const double eps=1e-12; const double PI=acos(-1.0); const double angcst=PI/180.0; const ll mod=998244353; ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);} ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;} ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;} ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;} struct node { string s; int i,j; //頁碼、位置 bool operator < (const node& a) const { if(i^a.i) return i<a.i; return j<a.j; } }str[1000050]; int ind[30]; //入度 bool to[30][30]; //連邊 bool vis[30]; //是否出現過該字母 void solve() { int n,k; cin>>n>>k; int tot=0; rep(i,1,n) { int id; cin>>id; rep(j,1,k) { ++tot; cin>>str[tot].s; for(char c:str[tot].s) vis[c-'a']=true; str[tot].i=id; str[tot].j=j; } } sort(str+1,str+1+tot); repp(i,1,tot) { int len=min(str[i].s.size(),str[i+1].s.size()); bool flag=false; repp(j,0,len) { if(str[i].s[j]!=str[i+1].s[j]) { int a=str[i].s[j]-'a'; int b=str[i+1].s[j]-'a'; if(!to[a][b]) ind[b]++; to[a][b]=true; //a->b連邊 flag=true; break; } } if(!flag) { if(str[i].s.size()>str[i+1].s.size()) //如果i+1是i的字首,顯然不存在解 { cout<<"IMPOSSIBLE\n"; return; } } } int siz=0; repp(i,0,26) siz+=(vis[i]?1:0); queue<int> q; vector<int> ans; repp(i,0,26) if(vis[i]&&ind[i]==0) //挑選入度為0的點 q.push(i); while(!q.empty()) { int cur=q.front(); q.pop(); ans.pb(cur); repp(it,0,26) { if(to[cur][it]) { ind[it]--; if(ind[it]==0) q.push(it); } } } if(ans.size()!=siz) { cout<<"IMPOSSIBLE\n"; return; } for(int it:ans) cout<<char(it+'a'); } int main() { closeSync; //multiCase { solve(); } return 0; }