(
柱爺有乙個字串s,對於其中的每乙個不同子串\(s^\ast\),柱爺都能o(1)
的得到這些字串的所有匹配位置
即能知道所有的[l,r]
區間使得 \(s[l,r]=s^\ast\),然後柱爺會把這些[l,r]區間的每個位置做上標記,如果最後這些標記位置形成了k個連通塊,那麼它對答案的貢獻就是1
柱爺早就知道了答案,但他現在想問你知道嗎?
輸入第一行乙個字串s,只有小寫字母,保證\(|s|≤10^5\)
接下來一行乙個k
,保證\(1≤k≤|s|\)
輸出一行表示答案
abaab
2對於ababa的字串aba它對所有字元都打上了標記,所以只有1個聯通塊
對於每乙個不同字串,對他的每乙個出現位置的每乙個字元都打上標記,形成k個聯通塊答案加1。
換個角度,如果我們知道了sam字尾自動機裡面每個節點的right集,對於每乙個right集,我們就可以知道乙個字串長度區間使這個集合形成k個聯通塊,再和這個節點的接受長度區間取個交就是這個節點的所有可行解。
串長度有1e5,對於全是a資料,他的right集和的個數達到1e10,顯然暴力出right集是不行的。
那麼我們可以用set的維護right集,用平衡樹維護right的差分陣列,維護出來後對於差分陣列我們只要求第size-k的大小就可以算得貢獻。最後用啟發式合併一下,雖然總體是nloglog,但在字尾樹上的啟發式跑得很快。
如果是隨機資料,那麼直接用set爆出right集應該也是沒有問題的。
//#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
long double esp=1e-11;
//#pragma comment(linker, "/stack:1024000000,1024000000")
#define fi first
#define se second
#define all(a) (a).begin(),(a).end()
#define cle(a) while(!a.empty())a.pop()
#define mem(p,c) memset(p,c,sizeof(p))
#define mp(a, b) make_pair(a, b)
#define pb push_back
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
typedef long long int ll;
const long double pi = acos((long double)-1);
const ll inf=0x3f3f3f3fll;
const int mod =1000000007ll;
const int maxn=100100;
int cnt,rot[maxn<<1]; //可重複,s表示節點的值的個數
struct treaptr[maxn*50];
inline void updata(int a)
inline int newtreap(int _val)
void init()
int merge(int a,int b)else
return y;
}int findkth(int t,int k)
void delete(int k,int t)
void pr(int t)
#define len 101000
#define alp 26
int pa[len<<1],son[len<<1][alp],right[len<<1];
int max[len<<1],cnt,root,last; //0為null節點,null只能到null
inline int newnode(int _max)
inline void pre()
inline void sam(int alp,int t) //注意t=26,s[x]-'a',多串時每次last=root
//已有狀態,對所有父狀態更新
else np=newnode(max[last]+1);
right[np]=t;
while(u&&!son[u][alp])son[u][alp]=np,u=pa[u];
if(!u)pa[np]=root;
else
}last=np;
}char s[maxn];
int k;
ll ans=0;
vectornode[maxn<<1];
setq[maxn<<1];
set::iterator iter,it;
int pos[maxn<<1],cc=0;
void ins(int val,int t)
else
q[pos[t]].insert(val);
}void dfs(int u)
//printf("\nnode%d %d\n",u,mapos);
rot[u]=rot[mapos];
if(mapos)pos[u]=pos[mapos];
else pos[u]=cc++,q[pos[u]].clear(),q[pos[u]].insert(-maxn*2);
if(right[u])ins(right[u],u);
for(int x:node[u])
if(x!=mapos)
if(tr[rot[u]].size>=k)
}// printf("%d %d %d\n",u,pa[u],right[u]);
// for(int val:q[pos[u]])printf("%d ",val);puts("");
// pr(rot[u]);puts("");
//答案
}void test()
for(int x=0;x<=cnt;x++)
node[x].clear();
init();
for(int x=1;x<=cnt;x++)
if(pa[x])
node[pa[x]].pb(x);
dfs(1);
}int main()
CDOJ1357 柱爺與最大區間和
傳送門 分析 首先,我們需要知道怎麼求一段最大區間和。從左往右掃的時候,用pre記錄當前的最大值,f i 表示從最左端到i這個區間上的最大和。當掃到i時,如果pre已經小於0,那麼直接將a i 賦值給pre,否則加上a i 然後f i max f i 1 pre 時間複雜度為o n 求兩段的話,再倒...
CDOJ 2016 B 柱爺與最大區間和
柱爺愛思考,凡事喜歡舉一反三,常常能想到別人沒想過的問題。比如最大區間和這個問題 在一數列上選出一段區間,使得這段區間和最大。柱爺想 如果選出兩段區間 不相鄰 會怎樣呢?柱爺很快想到了答案,你呢?input 第一行輸入乙個數n,表示陣列的長度。第二行輸入n個數,表示各元素的值。資料保證 3 n 50...
CDOJ 1401 譚爺的黑暗沙拉 數學
譚爺有 n 種不同種類的食材 水果 蔬菜 他想做出乙份總重量為 k 的黑暗沙拉。他想讓機智的你告訴他,他能做多少種不同的黑暗沙拉!說明 1.可以重複選擇食材,而且不需要選完全部的 n 種食材,但是最後總重量必須是 k 2.兩份沙拉不同,當且僅當 k 重量食材的種類或配比不同。3.每種食材只能選擇非負...