1. 程式人生 > >uva1610 聚會遊戲(細節處理)

uva1610 聚會遊戲(細節處理)

cout pac const ets 部分 max names pre pos

uva1610 聚會遊戲(細節處理)

輸入一個n(n<=1000且為偶數)個字符串的集合D,找一個長度最短的字符串(不一定要在D中出現)S,使得D中恰好一半字符串小於等於S,另一半大於S。如果有多解,輸出字典序最小的解。

首先找到兩個中位字符串S1和S2。顯然,答案S必須夾在S1和S2之間。由於要找最短的字符串,我們可以用叠代加深的思路,根據|S|叠代加深枚舉。每次枚舉長度時,必須保證S的前|S|-1位和S1相同,然後最後一位枚舉26個字符。這是一個貪心,應該不難證。我用了第k大數和跳過公共前綴部分來加速。

#include <cstdio>
#include <string>
#include <iostream> using namespace std; const int maxn=1005; int n; string a[maxn], s1, s2; void getstr(int l, int r, int ord, string &str){ if (l>=r) return; string base=a[(l+r)>>1]; int now=l; for (int i=l; i<r; ++i) //比base小的區間是[l,tmp) if (a[i]<base) swap(a[i], a[now++]); int
tmp=now; for (int i=tmp; i<r; ++i) //等於base的區間是[tmp,now) if (a[i]==base) swap(a[i], a[now++]); if (ord<tmp) getstr(l, tmp, ord, str); else if (ord>=now) getstr(now, r, ord, str); else str=a[tmp]; } string getpre(string s1, string s2){ string s(""); if
(s1.size()>s2.size()) swap(s1, s2); for (int i=0; i<s1.size(); ++i) if (s1[i]==s2[i]) s+=s1[i]; else break; return s; } int main(){ //註意半開區間取中值的方法和閉區間不同! while (~scanf("%d", &n)&&n){ for (int i=0; i<n; ++i) cin>>a[i]; //獲取兩個中位字符串 復雜度O(n|s|) s=30 getstr(0, n, n/2-1, s1); getstr(0, n, n/2, s2); string s=getpre(s1, s2); int cur=s.size(); if (s>=s1&&s<s2){ cout<<s<<endl; continue; } while (true){ for (char c=s[cur]; c<='Z'; ++c) if (s+c>=s1&&s+c<s2){ cout<<s+c<<endl; goto end; } s+=s1[cur++]; } end:; } return 0; }

uva1610 聚會遊戲(細節處理)