Problem 1. Redistricting
will\(H\)Regard\(+1\),\(G\)Regard\(-1\)To obtain a prefix and an array\(sum_i\)
Remember\(dp_i\)To take into account\(i\)When the answer, there is\(dp_i=min(dp_j+[sum_i-sum_j\leq 0])\)
direct\(dp\)the time is\(O(nk)\)Using optimization queues monotonically reduced time complexity\(O(nlog_2k)\)
Note monotone queue, the first key is a key bis\(dp\)The second is\(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 after tree just appeared a ring
To join two such non-tree edges\((u_1,v_1),(u_2,v_2)\)After forming a ring containing the two sides, the original two paths must cross ringlet
Problem into a number of\((u_1,v_1).(u_2,v_2)\)The two paths meet in the tree has a side cross-
Consider a one-dimensional problem: given\(n\)Intervals\([L_i,R_i]\), Asked how many have the intersection of range
Method: For each\(L_x\)The answer is subtracted\(L_i<L_x\)Intervals; for each\(R_x\)The answer plus\(L_I<R_x\)The interval number, this is the case for a range\([L_x,R_x]\)We counted all\(L_x\leq L_i\leq R_x\)Range, in line with the definition of the interval post
Implementation: We thought the analogy of the difference in the\(L_i\)At marked\(+1\)of\(tag\)And then do it again and prefixes. Note that pre-out\(L_i=L_j\)Case
In the trees, we will route\((u,v)\)split into\((u,lca)\)with\((v,lca)\)Do it all over again a tree difference + prefix tree and can
Specifically, a path for\((u,lca)\)We find\(lca\)Son on the path\(p\),in\(p\)On a hit\(+1tag\)To
Note that avoid double-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)]++;
} // prevented (u_1, v_1) (u_2, v_2) 2 groups denoted by
}
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
Have some difficulty thinking\(dp\)question
Remember all number\(a_1,a_2,\cdots,a_n\)
Note that when\(c_i\neq c_{i+1}\)When we can determine certain number, which inspired me to think about it a while\(c\)Value of the same consecutive segments
Suppose we have a great continuous segment\(c_i=c_{i+1}=\cdots=c_j=v\), They can affect the number of a total of\(j-i+k\)More
Remember\(f_i\)Imperatives\(a_i=v\)When the program number, write\(p=10^9-v\),violence\(dp\)Then that is one of the enumeration\(v\)A position that\(f_i=\sum_{j=i-k}^{i-1}p^{i-j-1}f_j\)Obviously timeout
Optimization, then consider that the above equation for offset subtraction, to give\(f_i=(p+1)f_{i-1}-p^kf_{i-k-1}\). The actual significance of this equation, the first\(i-1\)Can take any number (not necessarily limited to\(v\)) The number of schemes, minus\([i-1,i-k]\)It is greater than the number\(v\)The number of illegal schemes, time complexity\(O(n)\),acceptable
The next step is to prevent\(a_i\)It is repeated consideration or is not considered, if\(c_{i-1}>c_i\)It can be seen as\(a_{i+k-1}\)It has been identified, and it has been in the previous number\(c_{i-1}\)Are taken into account (because\(a_{i+k-2}...a_i\geq c_{i-1}>c_i\)), Calculated at this time\(a\)It will reduce the length of a\(k\),for\(c_{j+1}>c_j\)The same is true
Last is the length of\(len\)Answer sequence should be\(f_{len+1}\)Because we did not enforce\(a\)The last one is\(v\)
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;
}