(搜索+剪枝)
題意:給定
這個題目有很多解法,正解是後綴數組。(目前我只想出怎麼用搜索解這個題)
思路1(搜索+剪枝):
若想數字較大,那麼這個數字的最高位越大越好,再是次高位,再次次高…那麼我們可以先找出這些點中權值最大的點作爲起始點放入隊列中,然後一步步做廣度優先搜索,依次排除組成數字較小的起始點。最後剩下的那個點就是答案。
但是這個肯定超時,複雜度最大爲
於是朝這個方向優化:
1.同一層(step)裏,我們只要那些當前權值最大的點對應的起始點。
2.對於鏈的分支而言:假如初始點
3.對於環而言,假如一個點搜索了一圈最後到自身,那麼我們便可以斷定這個點是最優的(想想爲什麼)。
這三個優化缺一個都超時OTZ,折騰了我幾個小時…
思路2(後綴數組):待更
思路3(暴力枚舉):
仔細觀察圖,這個圖裏面環很多,暴力枚舉每一個起始點,判斷前幾十位找出數字最大的點對應的起始點即可。
代碼1:
#include <cstdio>
#include <queue>
#include <cctype>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 150010;
// to whom the point blg(belong);
// rid = 1: means I can get rid of this point
int blg[maxn], rid[maxn];
int to[maxn], pre[maxn], mx_value[maxn];
char w[maxn];
struct node {
int st_pos, cur_pos;
node(int a=0, int b=0):st_pos(a),cur_pos(b){}
};
//queue<node> Q;
node Q[maxn<<1], tmp_que[maxn<<1];
int r;
void solve(int cs) {
//init
r = 0;
int n;
scanf("%d",&n); getchar();
gets(w);
for(int i=0; i<n; i++) {
int v = ((LL)i*i + 1LL) % (LL)n;
to[i] = v; pre[v] = i;
Q[r++] = node(i, i);
rid[i] = 0;
mx_value[i] = blg[i] = -1;
}
//solve
int step = 0, ans = -1;
while(r > 1) {
int sz = 0;
// find the max number in the current step
for(int i=0; i<r; i++) {
node u = Q[i];
if(rid[u.st_pos]) continue ;
if((int)w[u.cur_pos] < mx_value[step]) continue ;
if((int)w[u.cur_pos] > mx_value[step]) {
mx_value[step] = (int)w[u.cur_pos];
sz = 0;
}
int v = to[u.cur_pos];
if(blg[v] != -1) rid[blg[v]] = 1;
tmp_que[sz++] = node(u.st_pos, v);
}
// put these point into the queue again, step ++;
for(int i=0; i<sz; i++) {
Q[i] = tmp_que[i];
int last = pre[Q[i].cur_pos];
blg[last] = Q[i].st_pos;
if(Q[i].st_pos == Q[i].cur_pos) {
ans = Q[i].st_pos;
break ;
}
}
if(ans != -1) break ;
r = sz;
step ++; if(step >= n) break ;
}
// get the best starting point
node u = Q[0];
printf("Case #%d: ",cs);
int pos = u.st_pos;
if(ans != -1) pos = ans;
for(int i=0; i<n; i++) {
putchar(w[pos]);
pos = to[pos];
}
puts("");
}
int main() {
int cs, tot = 0;
scanf("%d",&cs);
while(cs --)
solve(++tot);
return 0;
}