題目連接node
設最遠關鍵點距離爲\(d\),那麼答案就是\(\lceil\frac{d}{2}\rceil\)。
直接換根胡亂dp也行。。
ios
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+10; vector<int>g[maxn]; int vis[maxn]; int len,st,ed; void dfs(int u,int fa,int dep){ if(vis[u]){ if(dep>len){ len=dep; ed=u; } } for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v==fa)continue; dfs(v,u,dep+1); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,k; cin>>n>>k; for(int i=1;i<n;i++){ int u,v; cin>>u>>v; g[u].push_back(v),g[v].push_back(u); } for(int i=1;i<=k;i++){ cin>>st; vis[st]=1; } len=1,ed=st; dfs(st,0,1); st=ed; dfs(st,0,1); cout<<len/2<<endl; }
聽說是個線性基交的板子題,但仍是有一大波神仙A了。。
求交的話大概就是對於兩個基集合\(B1,B2\),枚舉\(B2\)中的基,若是與\(B1\)線性無關,那麼就插在\(B1\)裏面去;不然就對於當前的基,異或掉\(B1\)中以前插進去的\(B2\)的基,而後將其插入交集裏面就好了。證實的話能夠看看博客:傳送門
c++
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned int ui; const int N = 50005; int n, m; struct node{ ui r[32], f[32]; bool ins(ui x) { for(int i = 31; i >= 0; i--) { if(x >> i) { if(!r[i]) {r[i] = x; return 1;} else x ^= r[i]; } } return 0; } bool ins2(ui x) { ui tmp = x; for(int i = 31; i >= 0; i--) { if(x >> i) { if(!r[i]) {r[i] = x; f[i] = tmp; return 1;} else { x ^= r[i]; tmp ^= f[i]; } } } return 0; } void clear() { for(int i = 0; i <= 31; i++) r[i] = f[i] = 0; } bool find(ui x) { for(int i = 31; i >= 0; i--) { if(x >> i) { if(!r[i]) return 0; x ^= r[i]; } } return x == 0; } int calc(ui x) { int ans = 0; for(int i = 31; i >= 0; i--) { if(x >> i) { x ^= r[i]; ans ^= f[i]; } } return ans; } }; node _merge(node u, node v) { node tmp, res; res.clear(); tmp = u; for(int i = 31; i >= 0; i--) { ui x = v.r[i]; if(tmp.find(x)) { res.ins(x ^ tmp.calc(x)); } else tmp.ins2(x); } return res; } ui a[N][33]; node b[N << 2]; void build(int o, int l, int r) { if(l == r) { b[o].clear(); for(int j = 1; j <= 32; j++) b[o].ins(a[l][j]); return ; } int mid = (l + r) >> 1; build(o << 1, l, mid); build(o << 1|1, mid + 1, r); b[o] = _merge(b[o << 1], b[o << 1|1]); } bool query(int o, int l, int r, int L, int R, ui v) { if(L <= l && r <= R) { return b[o].find(v); } int mid = (l + r) >> 1; bool ans = 1; if(L <= mid) ans &= query(o << 1, l, mid, L, R, v); if(R > mid) ans &= query(o << 1|1, mid + 1, r, L, R, v) ; return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; for(int i = 1; i <= n; i++) { int k; cin >> k; for(int j = 1; j <= k; j++) cin >> a[i][j]; } build(1, 1, n); for(int i = 1, l, r; i <= m; i++) { ui x; cin >> l >> r >> x; if(query(1, 1, n, l, r, x)) cout << "YES" << '\n'; else cout << "NO" << '\n'; } return 0; }
南昌網絡賽出過,單調棧+線段樹維護就行。
數組
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ld; const int MAXN = 3e6 + 5, MAXM = 2e4 + 5, BOUND = 2e5 + 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f, base = 10000; const ll INFL = 0x3f3f3f3f3f3f3f3f; const double PI = acos(-1.0), eps = 1e-9; #define mid l + ((r-l)>>1) #define lson o<<1,l,m #define rson o<<1|1,m+1,r #define lc(x) ch[x][0] #define pii pair<int,int> #define vi vector<int> #define RR register int #define rc(x) ch[x][1] #define rep(i,a,b) for(RR i=(a);i<=(b);++i) #define random(a,b) ((a)+rand()%((b)-(a)+1)) struct Istream { template <class T> Istream &operator >>(T &x) { static char ch; static bool neg; for (ch = neg = 0; ch < '0' || '9' < ch; neg |= ch == '-', ch = getchar()); for (x = 0; '0' <= ch && ch <= '9'; (x *= 10) += ch - '0', ch = getchar()); x = neg ? -x : x; return *this; } }fin; struct Ostream { template <class T> Ostream &operator <<(T x) { x < 0 && (putchar('-'), x = -x); static char stack[233]; static int top; for (top = 0; x; stack[++top] = x % 10 + '0', x /= 10); for (top == 0 && (stack[top = 1] = '0'); top; putchar(stack[top--])); return *this; } Ostream &operator <<(char ch) { putchar(ch); return *this; } }fout; int n, a[MAXN], b[MAXN], l1[MAXN], r1[MAXN], st[MAXN], top = 0; ll maxv[MAXN << 2][2], minv[MAXN << 2][2], s[MAXN], s2[MAXN]; inline void pushUp(int o) { rep(i, 0, 1) { maxv[o][i] = max(maxv[o << 1][i], maxv[o << 1 | 1][i]); minv[o][i] = min(minv[o << 1][i], minv[o << 1 | 1][i]); } } void build(int o, int l, int r) { if (l == r) { maxv[o][0] = minv[o][0] = s[l]; maxv[o][1] = minv[o][1] = s2[l]; return; } int m = mid; build(lson); build(rson); pushUp(o); } ll query(int o, int l, int r, int L, int R, int t, int t2) { if (l >= L && r <= R) { if (t == 0)return minv[o][t2]; else return maxv[o][t2]; } int m = mid; ll ans; if (t == 0) { ans = INFL; if (L <= m)ans = min(ans, query(lson, L, R, t, t2)); if (R > m)ans = min(ans, query(rson, L, R, t, t2)); } else { ans = -INFL; if (L <= m)ans = max(ans, query(lson, L, R, t, t2)); if (R > m)ans = max(ans, query(rson, L, R, t, t2)); } return ans; } int main() { //ios::sync_with_stdio(false); cin.tie(0); fin >> n; rep(i, 1, n)fin >> a[i]; rep(i, 1, n)fin >> b[i]; rep(i, 1, n)s[i] = s[i - 1] + b[i]; for (int i = n; i >= 1; i--)s2[i] = s2[i + 1] + b[i]; build(1, 0, n + 1); // 左邊第一個比當前小 st[0] = 0; rep(i, 1, n) { while (top &&a[st[top]] >= a[i])top--; l1[i] = st[top]; st[++top] = i; } st[0] = n + 1; top = 0; // 右邊第一個比當前小 for (int i = n; i >= 1; i--) { while (top &&a[st[top]] >= a[i])top--; r1[i] = st[top]; st[++top] = i; } ll ans = -INFL; rep(i, 1, n) { if (a[i] > 0) { ll tmp = a[i] * (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) + s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - b[i]); //printf("%d %lld %lld %lld\n", i, query(1, 0, n + 1, l1[i], i, 0, 0), query(1, 0, n + 1, i, r1[i], 0, 1), (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) + //s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - a[i])); ans = max(ans, tmp); } else { ll tmp = a[i] * (s[i] - query(1, 0, n + 1, l1[i], i, 1, 0) + s2[i] - query(1, 0, n + 1, i, r1[i], 1, 1) - b[i]); //printf("%d %lld %lld %lld\n", i, query(1, 0, n + 1, l1[i], i, 0, 0), query(1, 0, n + 1, i, r1[i], 0, 1), (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) + //s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - a[i])); ans = max(ans, tmp); } } cout << ans << '\n'; return 0; }
這個題能夠往每一個二進制位上面去想,會發現有這樣一個式子:\(2^x\)%\(3!=0\),而且對於一個合法的\(a\),其二進制個數不會少於\(3\)。
由於模數爲3,因此能夠分狀況討論。
當\(a\)%\(3=0\)時,答案顯然爲一個;
當\(a\)%\(3=1\)時,由上面\(2^x\)%\(3!=0\)可知每一個二進制位模\(3\)要麼爲1,要麼爲2,而\(a\)是全部二進制位加起來,那麼湊出3的倍數也就取決於相關二進制的數量了。
因此就再分類討論一下:記\(cnt_i\)表示二進制位模3等於\(i\)的個數。以後對這個分類討論一下就好了。
詳見代碼吧:
網絡
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 64; ll a; int T; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> T; while(T--) { cin >> a; if(a % 3 == 0) { cout << 1 << ' ' << a << '\n'; continue; } cout << 2 << ' ' ; vector <int> v1, v2; for(int i = 0; i < N; i++) { if(!(a >> i & 1)) continue; if((1LL << i) % 3 == 1) v1.push_back(i); else v2.push_back(i); } if(a % 3 == 1) { if((int)(v1.size()) >= 2) { cout << a - (1LL << v1[0]) << ' ' << a - (1LL << v1[1]) << '\n'; } else if((int)v1.size() == 1) { cout << a - (1LL << v1[0]) << ' ' << (1LL << v1[0]) + (1LL << v2[0]) << '\n'; } else { cout << (1LL << v2[0]) + (1LL << v2[1]) + (1LL << v2[2])<< ' ' << a - (1LL << v2[0]) - (1LL << v2[1]) << '\n'; } } else { if((int)(v2.size()) >= 2) { cout << a - (1LL << v2[0]) << ' ' << a - (1LL << v2[1]) << '\n'; } else if((int)v2.size() == 1) { cout << a - (1LL << v2[0]) << ' ' << (1LL << v2[0]) + (1LL << v1[0]) << '\n'; } else { cout << (1LL << v1[0]) + (1LL << v1[1]) + (1LL << v1[2])<< ' ' << a - (1LL << v1[0]) - (1LL << v1[1]) << '\n'; } } } return 0; }
對於一個字符串,若是同時存在\(a\)和\(rev(a)\),咱們只求出本質不一樣的子串,它們會被算兩次,而其他的沒有\(rev\)的就會只算一次。
可是這個題目中\(a\)和\(rev(a)\)只會被計算一次。可是觀察到若是後面拼接一個反串,那麼\(a\)和\(rev(a)\)一樣被計算兩次,而其他的也會被計算兩次,但迴文串除外。
那麼咱們須要作得就是用後綴數組獲得拼接事後本質不一樣的串,但不算上中間拼接字符,設爲\(p\);另外考慮迴文串只會被計算一次,因此加上串中迴文串的數量\(q\)。那麼最終答案就是\(\frac{p+q}{2}\)。
代碼以下:
dom
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 4e5 + 5; char s[N]; namespace SA{ //sa:1...n Rank:0...n-1 int x[N], y[N], sa[N], c[N], height[N], Rank[N]; int f[N][20], lg[N]; int n; //length void da(char *s, int m){ n++; for(int i = 0; i < m; i++) c[i] = 0; for(int i = 0; i < n; i++) c[x[i] = s[i]]++; for(int i = 1; i < m; i++) c[i] += c[i - 1] ; for(int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i; for(int k = 1; k <= n; k <<= 1) { int p = 0 ; for(int i = n - k; i < n; i++) y[p++] = i ; for(int i = 0; i < n; i++) if(sa[i] >= k) y[p++] =sa[i] - k; for(int i = 0; i < m; i++) c[i] = 0; for(int i = 0; i < n; i++) c[x[y[i]]]++; for(int i = 1; i < m; i++) c[i] += c[i - 1]; for(int i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i] ; swap(x , y); p = 1; x[sa[0]] = 0; for(int i = 1; i < n; i++) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p - 1 : p++; if(p >= n) break ; m = p; } n--; int k = 0; for(int i = 0; i <= n; i++) Rank[sa[i]] = i; for(int i = 0; i < n; i++) { if(k) k--; int j = sa[Rank[i] - 1]; while(s[i + k] == s[j + k]) k++; height[Rank[i]] = k; } } ll count() { ll ans = 0; for(int i = 1; i <= n; i++) ans += n - sa[i] - height[i]; return ans; } void init() { for(int i = 2; i < N; i++) lg[i] = lg[i >> 1] + 1; for(int i = 2; i <= n; i++) f[i][0] = height[i]; for(int j = 1; j < 20; j++) for(int i = 2; i + (1 << j) - 1 <= n; i++) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]) ; } int get_lcp(int l, int r) { if(Rank[l] > Rank[r]) swap(l, r); l = Rank[l] + 1, r = Rank[r]; int k = lg[r - l + 1]; return min(f[l][k], f[r - (1 << k) + 1][k]); } } namespace PAM{ int ch[N][26], fail[N], len[N], st[N], cnt[N]; int sz, n, last; int New(int l, int f) { memset(ch[++sz], 0, sizeof(ch[sz])); len[sz] = l, fail[sz] = f; return sz; } void init() { sz = -1; New(0, 1); last = New(-1, 0); st[n = 0] = -1; memset(cnt, 0, sizeof(cnt)); } int getf(int x) { while(st[n - len[x] - 1] != st[n]) x = fail[x]; return x; } bool Insert(int c) { //int st[++n] = c; int x = getf(last); bool F = 0; if(!ch[x][c]) { F = 1; int f = getf(fail[x]); ch[x][c] = New(len[x] + 2, ch[f][c]); } last = ch[x][c]; cnt[last] = 1; return F; } void count() { for(int i = sz; i >= 1; i--) cnt[fail[i]] += cnt[i]; } }; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> s; int n = strlen(s); ll ans = 0; PAM::init(); for(int i = 0; i < n; i++) PAM::Insert(s[i] - 'a'); for(int i = 1; i <= PAM::sz; i++) ans += PAM::cnt[i]; s[n] = '&'; for(int i = n + 1; i <= 2 * n; i++) s[i] = s[2 * n - i]; s[n * 2 + 1] = '\0'; SA::n = 2 * n + 1; SA::da(s, 520); ans += SA::count(); ans -= 1ll * (n + 1) * (n + 1); cout << ans / 2; return 0; }
直接二維狀態的dijkstra跑一下就行,轉移的時候就相似於dp那樣,考慮當前這邊是否免費。考場上我zz了枚舉了一下,還好數據較小,否則GG。
ui
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 1e3 + 5; int n, m, S, T, k; struct edge{ int u, v, w; bool operator < (const edge &A)const { return w < A.w; } }E[N]; struct Edge{ int u,v,w,next ; }e[N << 1]; int tot, head[N]; int W[N][N]; struct node{ int d, u, c; bool operator < (const node &A)const{ return d>A.d; } }; void adde(int u,int v,int w){ e[tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++; } int d[N]; bool vis[N]; bool Dijkstra(int s){ priority_queue <node> q; memset(d,INF,sizeof(d)); memset(vis,0,sizeof(vis));d[s]=0; q.push(node{0, s, 0}); while(!q.empty()){ node cur = q.top();q.pop(); int u=cur.u; vis[u]=1; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(d[v]>d[u]+e[i].w && cur.c + (e[i].w == 0) <= k){ d[v]=d[u]+e[i].w; q.push(node{d[v],v, cur.c + (e[i].w == 0)}); } } } return d[T] != INF; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m >> S >> T >> k; int tmp = 0; for(int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; if(u == v) continue; if(u > v) swap(u, v); if(W[u][v]) W[u][v] = min(W[u][v], w); else W[u][v] = w; } for(int i = 1; i <= n; i++) for(int j = i + 1; j <= n; j++) if(W[i][j]) E[++tmp] = edge{i, j ,W[i][j]}; m = tmp; sort(E + 1, E + m + 1); int ans = INF; for(int i = m; i >= 1; i--) { memset(head, -1, sizeof(head)); tot = 0; for(int j = i; j <= m; j++) { adde(E[j].u, E[j].v, 0); adde(E[j].v, E[j].u, 0); } for(int j = 1; j < i; j++) { adde(E[j].u, E[j].v, E[j].w); adde(E[j].v, E[j].u, E[j].w); } if(Dijkstra(S)) ans = min(ans, d[T]); } cout << ans << '\n'; return 0; }
簽到題,dp或者維護前綴模3的值均可以作。
this
#include<bits/stdc++.h> typedef long long ll; const int MAXN = 1e5 + 5, MAXM = 1e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353; const ll INFL = 0x3f3f3f3f3f3f3f3f; using namespace std; const int oo = (1e9) - (1e6); #define lson o<<1,l,m #define rson o<<1|1,m+1,r #define mid l + ((r-l)>>1) #define pb push_back #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define all(v) (v.begin(),v.end()) typedef long double db; char s[MAXN]; int n, cnt[MAXN], pre[MAXN]; int main() { cin >> (s + 1); n = strlen(s + 1); int sum = 0; ll ans = 0; for (int i = 1; i <= n; i++) { sum = (sum * 10 + s[i] - '0') % 300; if ((sum - pre[i - 1] * 10 % 300 + 300) % 300 == 0)ans++; if (sum == 100)ans += cnt[1]; else if (sum == 200)ans += cnt[2]; else if (sum == 0)ans += cnt[0]; if (i - 1 >= 0)cnt[pre[i - 1] % 3]++; pre[i] = sum; } cout << ans << '\n'; return 0; }