题目连接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; }