颓了这么多天,终于重新开始写模拟赛blog了.
诶今天是模拟赛day几来着???
T1:
题目大意:给定一个矩阵表示,若为0表示为空地,为1表示障碍.再给出一个移动序列LRUD分别表示向左向右向上向下.问最少去掉几个移动序列的字符可以使得移动不出边界且不经过障碍.
考场得分:100.
数据可以支持的算法,所以考虑DP,而且很显然这是一个DP,所以直接设表示移动序列上到第个字符,目前在网格上的坐标为的最多保留字符数量.
发现状态只会影响到状态,所以可以用更新状态和,并用滚动数组优化.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=400,INF=(1<<29)-1;
int ri(){
int x=0;
char c=getchar();
for (;c<'0'||c>'9';c=getchar());
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x;
}
char rc1(){
char c=getchar();
while (c<'0'||c>'9') c=getchar();
return c;
}
char rc2(){
char c=getchar();
while (c<'A'||c>'Z') c=getchar();
return c;
}
int f[2][N+9][N+9],use[2][N+9][N+9],old,now,ans;
int b[N+9][N+9],x[N+9],y[N+9],n,m,k;
Abigail into(){
n=ri();m=ri();k=ri();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
b[i][j]=rc1()-'0';
for (int i=1;i<=k;++i)
switch (rc2()){
case 'L':
x[i]=0;y[i]=-1;
break;
case 'R':
x[i]=0;y[i]=1;
break;
case 'U':
x[i]=-1;y[i]=0;
break;
case 'D':
x[i]=1;y[i]=0;
break;
}
}
Abigail work(){
for (int i=1;i<=n;++i)
b[i][0]=b[i][m+1]=1;
for (int i=1;i<=m;++i)
b[0][i]=b[n+1][i]=1;
old=1;now=0;
use[old][1][1]=1;
f[old][1][1]=0;
for (int g=0;g<k;++g){
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
use[now][i][j]=f[now][i][j]=0;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (use[old][i][j]){
f[now][i][j]=max(f[now][i][j],f[old][i][j]);
use[now][i][j]=1;
if (b[i+x[g+1]][j+y[g+1]]) continue;
use[now][i+x[g+1]][j+y[g+1]]=1;
f[now][i+x[g+1]][j+y[g+1]]=max(f[now][i+x[g+1]][j+y[g+1]],f[old][i][j]+1);
}
now^=1;old^=1;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (use[old][i][j]) ans=max(ans,f[old][i][j]);
}
Abigail outo(){
printf("%d\n",k-ans);
}
int main(){
freopen("island.in","r",stdin);
freopen("island.out","w",stdout);
into();
work();
outo();
return 0;
}
T2:
题目大意:给出一串序列,现在问这个序列的第小区间和为多少.
考场得分:100分.
考场想了一小时,写了5分钟...
其实看到这种没什么数学模型,与数据结构和图论明显没什么关系的题就可以直接考虑DP和分治了.然后这道题DP想不到任何有用的性质,就考虑二分了.
很自然地想到二分第小的区间和,然后用一个的暴力枚举区间来判定,优秀地做到了比直接枚举区间还要慢的算法.
考虑优化,我们考虑枚举区间的右端点,很容易发现若左端点为时满足条件,那么属于区间的区间一定都满足条件,所以考虑二分维护,可以做到优秀的的算法.
然而这样还是不能做到满分.那么考虑枚举右端点时,左端点也一直往右移,那么直接维护即可.时间复杂度.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
const LL INF=(1LL<<62)-1LL;
LL a[N+9],sum[N+9],ans,k;
int n;
int ri(){
int x=0;
char c=getchar();
for (;c<'0'||c>'9';c=getchar());
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x;
}
int rl(){
LL x=0;
char c=getchar();
for (;c<'0'||c>'9';c=getchar());
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x;
}
bool check(LL mid){
int last=1;LL ans=0;
for (int i=1;i<=n;++i){
while (sum[i]-sum[last-1]>mid) last++;
ans+=i-last+1;
}
return ans>=k;
}
Abigail into(){
n=ri();k=rl();
for (int i=1;i<=n;++i){
a[i]=rl();
sum[i]=sum[i-1]+a[i];
}
}
Abigail work(){
ans=INF;
for (int i=61;i>=0;--i)
if (check(ans-(1LL<<i))) ans-=1LL<<i;
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
freopen("movie.in","r",stdin);
freopen("movie.out","w",stdout);
into();
work();
outo();
return 0;
}
T3:
题目大意:给定一棵树,以及若干点集,要求将点集中的点分成几个组,每个组只有两个点,使得每组的两点在树上的距离最小是否小于树的总点数,若小于输出方案.
考场得分:35分.(写链的部分分说是15分实际有35分贼开心^o^)
这道题貌似跟蓝书上的异象石很像啊,都用到了同一个结论.(然而我还是想了1个小时都不会)
首先我们考虑链的部分分,就可以发现距离一定不会超过树的总点数,并且一定是相邻两点分一组.
然后我们像异象石这题的做法一样,将所有点按照dfs序来排序,就可以发现:
其中ai为询问的点集,并且设.
所以两点之间连边肯定是取排序后相邻两点,那么就只会有两种不同的方案,在这两种方案里面必定有一种距离和小于等于n-1,那么取小的那种就可以了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200000;
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],top,n;
void ins(int x,int y){
e[++top].y=y;
e[top].next=lin[x];
lin[x]=top;
}
struct node{
int deep,dfn,top,fa,size,son;
}d[N+9];
int num=0;
void dfs1(int k,int fa){
d[k].fa=fa;
d[k].deep=d[fa].deep+1;
d[k].size=1;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa){
dfs1(e[i].y,k);
d[k].size+=d[e[i].y].size;
if (d[d[k].son].size<d[e[i].y].size) d[k].son=e[i].y;
}
}
void dfs2(int k,int top){
d[k].top=top;
d[k].dfn=++num;
if (d[k].son) dfs2(d[k].son,top);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^d[k].fa&&e[i].y^d[k].son) dfs2(e[i].y,e[i].y);
}
int LCA(int x,int y){
while (d[x].top^d[y].top)
d[d[x].top].deep>d[d[y].top].deep?x=d[d[x].top].fa:y=d[d[y].top].fa;
return d[x].deep<d[y].deep?x:y;
}
int s,tmp[N+9];
bool cmp(const int &a,const int &b){return d[a].dfn<d[b].dfn;}
Abigail into(){
scanf("%d",&n);
int x,y;
for (int i=1;i<n;++i){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
}
Abigail work(){
dfs1(1,0);
dfs2(1,1);
}
Abigail getans(){
#define dis(a,b) d[a].deep+d[b].deep-2*d[LCA(a,b)].deep
while (~scanf("%d",&s)&s){
for (int i=1;i<=s;++i)
scanf("%d",&tmp[i]);
sort(tmp+1,tmp+1+s,cmp);
int sum=0;
sum+=dis(tmp[1],tmp[s]);
for (int i=2;i<s;i+=2)
sum+=dis(tmp[i],tmp[i+1]);
puts("Yes");
if (sum<n){
printf("%d %d\n",tmp[1],tmp[s]);
for (int i=2;i<s;i+=2)
printf("%d %d\n",tmp[i],tmp[i+1]);
}else{
for (int i=1;i<s;i+=2)
printf("%d %d\n",tmp[i],tmp[i+1]);
}
}
}
int main(){
freopen("kieru.in","r",stdin);
freopen("kieru.out","w",stdout);
into();
work();
getans();
return 0;
}