USACO 2019 January Contest, Platinum Problem Solution

Keywords: PHP

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;
}

Posted by zildjohn01 on Tue, 23 Jul 2019 05:52:17 -0700