Problem 1. Redistricting
Consider (H) as (+1), (G) as (-1), and get a prefix and array (sum_i)
Note (dp_i) For the answer when (i), dp_i=min (dp_j+[sum_i-sum_j\\\\leq 0]\
The direct (dp) time is (O(nk), and the time complexity of monotone queue optimization is reduced to (O(nlog_2k)
Note that monotone queues are double-keyed, with the first keyword being(dp) and the second being(sum)
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<math.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define lowbit(x) (x)&(-x) #define sqr(x) (x)*(x) #define fir first #define sec second #define rep(i,a,b) for (register int i=a;i<=b;i++) #define per(i,a,b) for (register int i=a;i>=b;i--) #define maxd 1000000007 #define eps 1e-6 typedef long long ll; const int N=100000; const double pi=acos(-1.0); int n,k,dp[300300],sum[300500]; char s[300500]; struct hnode{int val,id;}; bool operator <(hnode p,hnode q) { if (p.val==q.val) return sum[p.id]>sum[q.id]; else return p.val>q.val; } priority_queue<hnode> q; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } int main() { freopen("redistricting.in","r",stdin); freopen("redistricting.out","w",stdout); n=read();k=read(); scanf("%s",s+1); rep(i,1,n) if (s[i]=='H') sum[i]=sum[i-1]+1;else sum[i]=sum[i-1]-1; memset(dp,0x3f,sizeof(dp));dp[0]=0; q.push((hnode){0,0}); rep(i,1,n) { while (q.top().id<i-k) q.pop(); dp[i]=q.top().val; if (sum[q.top().id]>=sum[i]) dp[i]++; q.push((hnode){dp[i],i}); } printf("%lld",dp[n]); return 0; }
Problem 2. Exercise Route
For a non-tree edge((u_1,v_1)), add it to a tree and a ring appears on the tree.
If two non-tree edges((u_1,v_1),(u_2,v_2)) are added to form a ring containing these two edges, the original two small ring paths must intersect.
The problem is transformed into how many pairs of ((u_1,v_1).(u_2,v_2)) satisfy that two paths on a tree have intersections.
Consider a one-dimensional problem: Give (n) intervals ([L_i,R_i]), and ask how many pairs of intervals intersect.
Practice: For each \((L_x\\\\\\\\\\\\\\\\\\\\\\\Definition of Intersection Compliance
Realization: Our idea of analogical difference is to mark (+1) on \\\\\\\\\\\ Note the case where (L_i=L_j)is preconditioned
On a tree, we split the path ((u,v)\) into ((u,lca)) and ((v,lca)\), so that we can do the difference on the tree + the prefix sum on the tree once.
Specifically, for a path ((u,lca)), we find a son (lca\) on that path \(p\) and type a (+1tag) on \)
Be careful to avoid repeated counting
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<math.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define lowbit(x) (x)&(-x) #define sqr(x) (x)*(x) #define fir first #define sec second #define rep(i,a,b) for (register int i=a;i<=b;i++) #define per(i,a,b) for (register int i=a;i>=b;i--) #define maxd 1000000007 #define eps 1e-6 #define mp make_pair typedef long long ll; typedef pair<int,int> pii; const int N=100000; const double pi=acos(-1.0); struct node{int to,nxt;}sq[400200]; int all=0,head[200200]; int n,m,sp[200200][2],fa[200200][20],dep[200200],lca[200200]; ll tag[200200],val[200200]; map<pii,int> tax; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } void add(int u,int v) { all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all; } void dfs1(int u,int fu) { dep[u]=dep[fu]+1;fa[u][0]=fu; rep(i,1,19) fa[u][i]=fa[fa[u][i-1]][i-1]; int i; for (i=head[u];i;i=sq[i].nxt) { int v=sq[i].to; if (v!=fu) dfs1(v,u); } } int LCA(int u,int v) { if (dep[u]<dep[v]) swap(u,v); int tmp=dep[u]-dep[v]; per(i,19,0) if ((tmp>>i)&1) u=fa[u][i]; if (u==v) return u; per(i,19,0) if (fa[u][i]!=fa[v][i]) {u=fa[u][i];v=fa[v][i];} return fa[u][0]; } int nxt(int u,int fu) { if (u==fu) return -1; per(i,19,0) if ((fa[u][i]) && (dep[fa[u][i]]>dep[fu])) u=fa[u][i]; return u; } void dfs2(int u,int fu) { val[u]=val[fu]+tag[u];int i; for (i=head[u];i;i=sq[i].nxt) { int v=sq[i].to; if (v!=fu) dfs2(v,u); } } int main() { freopen("exercise.in","r",stdin); freopen("exercise.out","w",stdout); n=read();m=read(); rep(i,1,n-1) { int u=read(),v=read(); add(u,v);add(v,u); } dfs1(1,0);ll ans=0; rep(i,n,m) { sp[i][0]=read();sp[i][1]=read(); lca[i]=LCA(sp[i][0],sp[i][1]); int nx=nxt(sp[i][0],lca[i]),ny=nxt(sp[i][1],lca[i]); if (nx!=-1) {tag[nx]++;ans-=tag[nx];} if (ny!=-1) {tag[ny]++;ans-=tag[ny];} if ((nx!=-1) && (ny!=-1)) { if (nx>ny) swap(nx,ny); ans-=tax[mp(nx,ny)];tax[mp(nx,ny)]++; }//Prevent (u_1,v_1)(u_2,v_2) from being recorded as two groups } dfs2(1,0); rep(i,n,m) { int u=sp[i][0],v=sp[i][1]; ans+=(val[u]+val[v]-val[lca[i]]*2); } printf("%lld\n",ans); return 0; }
Problem 3. Train Tracking 2
Question (dp) with some difficulty in thinking
Record all numbers as (a_1, a_2, cdots, a_n)
Notice that when u (c_i__ NEQ {i+1}__), we can determine certain numbers, which inspires us to consider a continuous segment with the same (c_) value.
Assuming that we have a maximal continuous segment (c_i=c_{i+1}=\cdots=c_j=v), then the number of total (j-i+k\)that they can affect is
Note (f_i) denotes the number of schemes for mandatory (a_i=v) and (p=10^9-v), violence (dp\) enumerates the last location of \(v), that is, \(f_i=\u sum {j=i-k} {i-1} P {i-j\u j), which is obviously overtime.
In optimization, we consider subtracting the above formula by dislocation to get (f_i=pf_{i-1}-p^kf_{i-k-1}\). In the practical sense of this formula, the number of (i-1\) can be arbitrarily selected (without restriction to (v). Subtracting the number of ([i-1,i-k]) is more than the number of (v) illegitimate schemes, and the time complexity\(O(n) is acceptable.
Next is to prevent \(a_i\) from being considered or not considered, if \ (c {i-1}>c_i\\\\\\\\\\i+k-1}\\\\\\\\\In this case, the calculated length of (a_) will be reduced by one (k_), for (c {j)+ The same is true for 1}>c_j)
Finally, the answer to a sequence of len length should be (f_{len+1}\), because we did not force (a\) to end with (v)
The code is very simple
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<math.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define lowbit(x) (x)&(-x) #define sqr(x) (x)*(x) #define fir first #define sec second #define rep(i,a,b) for (register int i=a;i<=b;i++) #define per(i,a,b) for (register int i=a;i>=b;i--) #define maxd 1000000007 #define eps 1e-6 typedef long long ll; const int N=1000000000; const double pi=acos(-1.0); int n,k,a[100100]; ll dp[100100]; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } ll qpow(ll x,int y) { ll ans=1; while (y) { if (y&1) ans=ans*x%maxd; x=x*x%maxd;y>>=1; } return ans; } ll solve(int val,int len) { dp[0]=1;dp[1]=1; int i;ll p=N-val,tmp=qpow(p,k); rep(i,2,len+1) { dp[i]=(p+1)*dp[i-1]%maxd; if (i-k-1>=0) dp[i]=(dp[i]-tmp*dp[i-k-1]%maxd+maxd)%maxd; } return dp[len+1]; } int main() { freopen("tracking2.in","r",stdin); freopen("tracking2.out","w",stdout); n=read();k=read(); rep(i,1,n-k+1) a[i]=read(); int ans=1,i,j=0; for (i=1;i<=n-k+1;i=j+1) { j=i; while ((j<=n-k+1) && (a[i]==a[j])) j++;j--; int len=j+k-i; if ((i>1) && (a[i]<a[i-1])) len-=k; if ((j<n-k+1) && (a[j]<a[j+1])) len-=k; if (len>0) ans=ans*solve(a[i],len)%maxd; } printf("%lld",ans); return 0; }