codeforces#475 div1
阿新 • • 發佈:2018-04-29
src 最小 can clas i++ ID swa 連接 mes
B.
非常有意思的題目,但一開始沒有想出來怎麽證明。有點偏向於離散數學證明題。
首先給出結論:當且僅當點的個數為奇數時可以構造出來一種刪除序列。
首先考慮證明必要性,每次刪除操作相當於在原先的樹上哢去偶數條邊,從而必然有點的個數為奇數。
考慮充分性,我們從深度較大的點到深度較小的點刪除,每次對於一個點x,我們要麽能將其子樹刪完,要麽剩余一個聯通的度數全都是奇數的子樹,必然可以通過上面的點刪除完。
這樣歸納到最後必然有形成的要麽是一個度數全為奇數的樹,要麽能刪空。
而對於一個度數全為奇數的樹,從一個點開始,歸納法:
一個可以刪空的子樹如果根的初始度數為奇數,則必然是連接到奇數個可刪空子樹,有偶數*奇數 = 奇數個初始度數為偶數的點。
另外三種情況同上,最終證明一個子樹能刪空 <=> 其中有奇數個初始度數為偶數的點。
而對於一個有奇數個點的樹,度數為偶數的點必然有奇數個。
得證。(貌似證麻煩了)
const int N = 200010; vector<int> g[N],g2[N]; int n, root, dep[N], d[N], ans[N], tot, fa[N]; bool del[N]; struct node { int x; bool operator < (const node &tmp) const { if(dep[x]!=dep[tmp.x]) returnView Codedep[x] > dep[tmp.x]; else return x < tmp.x; } }; set<node> St; void dfs(int x) { for(auto p:g[x]) { dep[p] = dep[x]+1; dfs(p); } } int main() { cin >> n; FOR(i,1,n) { scanf("%d",&fa[i]); if(fa[i] == 0) root = i;else g[fa[i]].pb(i), d[i]++, d[fa[i]]++; } dfs(root); FOR(i,1,n) if(d[i]%2==0) St.insert((node){i}); FOR(i,1,n) if(fa[i]) g[i].pb(fa[i]); while(!St.empty()) { int x = St.begin()->x; del[x] = 1; ans[++tot] = x; St.erase(St.begin()); for(auto p:g[x]) if(!del[p]){ if(--d[p]%2==0) St.insert((node){p}); else St.erase((node){p}); } } if(tot < n) cout << "NO" << endl; else { cout << "YES" << endl; FOR(i,1,tot) printf("%d\n",ans[i]); } return 0; }
C.
可以註意到對於任意一種初始矩形,我們只需要確認橫向切幾道,縱向切幾道,就可以確認初始矩形的大小。
對於任意一種切分方案,我們都可以通過調整將其變為如下方案:
D.
考慮只有 $\sqrt n$ 種不同的長度,並且有各個詢問串不同使得,如果我們采用 $O(當前字符出現次數)$ 的方法求最小長度,均攤下來復雜度 $O(n \sqrt n)$
問題在於求解出每個字符出現的位置,AC自動機上建出fail樹,而後啟發式合並即可。
$O(n \sqrt n + n log^2n)$
關鍵在於分析復雜度。
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(),(x).end() #define se second #define fi first #define debug(x) cerr << #x << " = " << x << endl; #define rep(i,s,t) for(int i=(s);i<=(t);i++) #define rrep(i,s,t) for(int i=(s);i>=(t);i--) #define SZ(x) ((int)(x).size()) #define pb push_back #define mp make_pair typedef pair<int,int> PII; typedef long long ll; const int mo = 1000000007; ll powmod(ll x,ll n) {ll re=1; for(;n;n>>=1,x=x*x%mo) if(n&1) re=re*x%mo; return re; } ll gcd(ll a,ll b) {return b? gcd(b,a%b):a;} //head const int N = 100000 + 10; struct node { node *ch[26],*fa; vector<PII> q; int id; }pool[N],*cur=pool,*rt=&pool[0]; int n,m,nps,ans[N],len[N]; char s[N],tp[N]; vector<int> g[N],vc[N]; void add(char *c,int id,int mi) { node *p = rt; while(*c!=‘\0‘) { if(!p->ch[*c-‘a‘]) p->ch[*c-‘a‘] = ++cur; p = p->ch[*c-‘a‘]; c++; } p->q.pb(mp(id,mi)); } queue<node*> q; void getfail() { q.push(rt); rt->fa = rt; for(auto i=&pool[0];i<=cur;i++) i->id = ++nps; while(!q.empty()) { node *p = q.front(); q.pop(); if(p->fa != p) g[p->fa->id].pb(p->id); rep(i,0,25) { if(p->ch[i]) { if(p!=rt) p->ch[i]->fa = p->fa->ch[i]; else p->ch[i]->fa = rt; q.push(p->ch[i]); } else { if(p!=rt) p->ch[i] = p->fa->ch[i]; else p->ch[i] = rt; } } } } set<int> son[N]; void dfs(int x,set<int>* &ch) { set<int> *ss = &son[x]; ch->clear(); for(auto p:vc[x]) ch->insert(p); for(auto p:g[x]) { ss->clear(); dfs(p,ss); if(ss->size() > ch->size()) swap(ss,ch); for(auto j=ss->begin();j!=ss->end();j++) ch->insert(*j); } if(!pool[x-1].q.empty()) { auto tt = pool[x-1].q.begin(); if(tt->se > (int)ch->size()) ans[tt->fi] = -1; else { ans[tt->fi] = n; vector<int> q; for(auto j=ch->begin();j!=ch->end();j++) q.pb(*j); rep(i,0,SZ(q)-tt->se) { ans[tt->fi] = min(ans[tt->fi], q[i+tt->se-1]-q[i]+len[tt->fi]); } } } } set<int> trp; int main() { int q,t; scanf("%s",s+1); n = strlen(s+1); scanf("%d",&q); rep(i,1,q) { scanf("%d%s",&t,tp); len[i] = strlen(tp); add(tp,i,t); } getfail(); node *tmp = rt; rep(i,1,n) { tmp = tmp->ch[s[i]-‘a‘]; vc[tmp->id].pb(i); } set<int> *tt = &son[0]; dfs(1,tt); rep(i,1,q) printf("%d\n",ans[i]); return 0; }View Code
codeforces#475 div1