这次模拟考试订正历程很悲催……
Solution
T1:很经典的二分答案,直接切掉
T2:听说过是DP,考试时先写了一个dfs,发现要记录前一个有没有选来看后面的是否连在一起,f[i][j][k][sta]表示A数组前i个,B数组前j个,分成k段,最后两个是否匹配的方案数,一开始忘记选了也可以分为2段,总的方程就是比较a[i+1]和b[j+1],若不同,只能推到f[i+1][j][k][0],若相同,a[i+1]可以不选,就是f[i+1][j][k][0],选,但是自成一段,a[i+1][j+1][k+1][1],或者与前面的合并,但是a[i]得选,f[i+1][j+1][k][1]。
T3:其实一开始不会,一直想不出去掉一条边后怎么计算所有的路径并统计,只会暴力的50分,后来看了题解……发现一开始思路错了,应该想二分,去判断比较简单,就把所有的不符合的路径拿出来,然后记录,然后取所有路径的交集中最长的一条边,看不符合条件的最长的一条路径是否符合即可,思路还算简单。实现上要用树上差分,就是对于路径(u,v),tmp[u]++,tmp[v]++,tmp[lca(u,v)]-=2,tmp[i]表示从i开始向上到根的路径有多少,统计的时候自底向上计算,实现是DFS,先算儿子,父亲tmp+=儿子tmp,记录tmp=cnt的节点,最后判断即可。
订正时遇到的问题:一直WA,吐血的那种,最后发现有些代码没有dfs(v,u),有些代码lca的k只到2(调试时改的),我去。
CODE
T1:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=50010;
int a[MAXN],L,n,m;
bool check(int k)
{
int last=0,cnt=0;
for (int i=1;i<=n;i++)
if (a[i]-last<k) cnt++;
else last=a[i];
if (L-last<k) cnt++;
return cnt<=m;
}
int main()
{
scanf("%d%d%d",&L,&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
int l=0,r=L;
while (l<r)
{
int mid=(l+r+1)>>1;
if (check(mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
T2:
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
char a[1010],b[210];
int f[2][205][2][205],n,m,K,ans,now;
int main()
{
scanf("%d%d%d",&n,&m,&K);
scanf("%s",a+1);
scanf("%s",b+1);
n=strlen(a+1); m=strlen(b+1);
f[0][0][0][0]=1; now=0;
for (int i=0;i<n;i++)
{
for (int j=0;j<=m;j++)
for (int k=0;k<=K;k++)
for (int sta=0;sta<=1;sta++)
{
int p=f[now][j][sta][k];
if (!p) continue;
f[1-now][j][0][k]=(f[1-now][j][0][k]+p)%MOD;
if (j<m && a[i+1]==b[j+1])
{
if (sta) f[1-now][j+1][1][k]=(f[1-now][j+1][1][k]+p)%MOD;
f[1-now][j+1][1][k+1]=(f[1-now][j+1][1][k+1]+p)%MOD;
}
f[now][j][sta][k]=0;
}
now=1-now;
}
ans=(f[now][m][0][K]+f[now][m][1][K])%MOD;
printf("%d\n",ans);
return 0;
}
T3:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=300010,MAXM=300010;
int Head[MAXN],tot,n,m,maxdeep,cnt,limit,ans;
int fa[MAXN],f[21][MAXN],deep[MAXN],dis[MAXN],tmp[MAXN];
struct Edge{
int v,d,next;
}edge[MAXN*2];
struct node{
int u,v,d,lca;
}e[MAXM];
void addedge(int x,int y,int z)
{
edge[++tot]=(Edge){y,z,Head[x]};
Head[x]=tot;
}
void dfs_pre(int u,int pre)
{
maxdeep=max(maxdeep,deep[u]);
for (int i=Head[u];i;i=edge[i].next)
{
int v=edge[i].v,d=edge[i].d;
if (v==pre) continue;
fa[v]=u; deep[v]=deep[u]+1; dis[v]=dis[u]+d;
dfs_pre(v,u);
}
}
int query_lca(int u,int v)
{
if (deep[u]<deep[v]) swap(u,v);
int step=deep[u]-deep[v];
for (int k=0;k<=20;k++)
if (step & (1<<k)) u=f[k][u];
for (int k=20;k>=0;k--)
if (f[k][u]!=f[k][v])
u=f[k][u],v=f[k][v];
return u==v?u:fa[u];
}
void calc_lca()
{
memset(f,-1,sizeof(f));
int k=log(n)/log(2);
for (int i=1;i<=n;i++) f[0][i]=fa[i];
for (int j=1;j<=k;j++)
for (int i=1;i<=n;i++)
if (f[j-1][i]!=-1) f[j][i]=f[j-1][f[j-1][i]];
for (int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v;
e[i].lca=query_lca(u,v);
e[i].d=dis[u]+dis[v]-2*dis[e[i].lca];
}
}
void init()
{
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
for (int i=1;i<=m;i++)
scanf("%d%d",&e[i].u,&e[i].v),e[i].d=0;
fa[1]=-1; deep[1]=1; dis[1]=0;
dfs_pre(1,1);
calc_lca();
}
int dfs(int u,int pre)
{
for (int i=Head[u];i;i=edge[i].next)
{
int v=edge[i].v,d=edge[i].d;
if (v==pre) continue;
dfs(v,u);
if (tmp[v]==cnt) ans=max(ans,d);
tmp[u]+=tmp[v];
}
return ans;
}
bool check(int mid)
{
memset(tmp,0,sizeof(tmp));
cnt=0,limit=0;
for (int i=1;i<=m;i++)
if (e[i].d>mid)
{
cnt++;
tmp[e[i].u]++;
tmp[e[i].v]++;
tmp[e[i].lca]-=2;
limit=max(limit,e[i].d-mid);
}
if (!cnt) return true;
ans=-1; dfs(1,0);
return ans>=limit;
}
void solve()
{
int l=0,r=300000000;
while (l<r)
{
int mid=(l+r)>>1;
if (check(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
int main()
{
//freopen("transport.in","r",stdin);
//freopen("transprot.out","w",stdout);
init();
solve();
return 0;
}