普及第六场题解报告
T1
*事实上T1可以打表,这使你充满了决心
#include<bits/stdc++.h>
using namespace std;
int n,sum,i=0,pw=1;
int main(){
scanf("%d",&n);
for(i=1;sum<n;++i,pw*=7){
sum+=pw;
if(sum>=n) break;
}
printf("%d",i);
return 0;
}T2
60%的数据:
考虑当前处在第的位置,分两类
第一类:直接走到的位置
第二类:先到一个传送门,再从传送门走到位置
复杂度为
100%的数据:
由于可以从一个位置到达所有传送门的位置
所以可以预处理数组表示从传送门出来到位置
的最短路
仍然分为两类
第一类:直接走到
第二类:
复杂度为
#include<bits/stdc++.h>
#define maxn 5010
#define INF 10000010
using namespace std;
int n,m,foot[maxn],X[maxn],Y[maxn],door[maxn],doors[maxn];//foot i 从i去往i+1
long long ans;
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d%d",&X[i],&Y[i]),doors[i]=INF;
for(int i=1;i<=m;++i) scanf("%d",&door[i]);
for(int i=1;i<=n;++i){
if(i<n) foot[i]=abs(X[i]-X[i+1])+abs(Y[i]-Y[i+1]);
for(int j=1;j<=m;++j){
int dis=abs(X[i]-X[door[j]])+abs(Y[i]-Y[door[j]]);
doors[i]=min(doors[i],dis);
}
}
for(int i=1;i<n;++i) ans+=1LL*min(doors[i+1],foot[i]);
printf("%lld",ans);
return 0;
}T3
subtask1
可以打表,但是很累
subtask2
通过dfs枚举每个小球移动的位置,暴力计算出答案
60%的数据
我们考虑这个字符会把整个板子分成许多的空间
对于每一个空间,空间的球是绝对无法到达其他空间的,且整个空间内部只有球和空格
所以对于每个空间的小球进行位置的枚举
我们考虑最优答案是向下移动最多的情况,
对于每一个空间
最终小球会堆积在底部,这肯定是最优的。
而且每次使一个能移动的小球填充最底下的空格,是不会造成道路堵塞的问题的。证明:若每一个小球都不能直接移动到底部,则这不满足一个空间的定义。
枚举这次堆积在底部的球是怎么移动得到的。
复杂度:未知
100%的数据
我们考虑一个空间中的球,个数为,他们的高度为
那么掉落掉底部后他们的高度为
最终得分为
即
所以不必再用dfs枚举每个小球的位置
#include<bits/stdc++.h>
#define maxn 300010
#define ll long long
using namespace std;
int n,nums,num;
ll sum1,sum2[maxn],ans;
bool Map[maxn][3],v[maxn][3],have[maxn][3];
void dfs(int y,int x){
if(x<1||x>2||y<1||y>n||v[y][x]||Map[y][x]) return;
v[y][x]=true;
if(have[y][x]) sum1+=1LL*y,++num;//计算h的总和
++nums;sum2[nums]=sum2[nums-1]+1LL*y;//计算k的前缀
dfs(y,x-1);//先考虑左右,再考虑上面,因为要使小球尽量堆积在底部
dfs(y,x+1);
dfs(y+1,x);
}
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%d",&n);
for(int i=n;i>=1;--i){
for(int j=1;j<=2;++j){
char c;
cin>>c;
if(c=='x') Map[i][j]=true;
if(c=='o') have[i][j]=true;
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=2;++j){
if(!v[i][j]){
dfs(i,j);
ans+=sum1-sum2[num];
while(nums--) sum2[nums]=0;
sum1=0,num=nums=0;
}
}
printf("%lld",ans);
return 0;
}T4
基本原理和T2一致
subtask1
dfs大法
subtask2
对于k=0的情况,每次跑单源最短路进行从到
的最短路线即可
60%的数据
如上述,可以用对每个点跑最短路,然后用T2同理的
进行记录,后分类即可
100%的数据
要堆优化的dij处理从每个位置出发的最短路
复杂度
#include<bits/stdc++.h>
#define maxn 2010
#define ll long long
#define INF 10000000000010
using namespace std;
int n,m,k,door[maxn];
ll foot[maxn],doors[maxn],ans;
struct EDGE{
int nxt,to;
ll dis;
}edge[maxn<<4];
int head[maxn],edge_num;
void add_edge(int from,int to,ll dis){
edge[++edge_num].nxt=head[from];
edge[edge_num].to=to;
edge[edge_num].dis=dis;
head[from]=edge_num;
}
ll dis[maxn];
struct node{
int drop;
ll dis_sum;
}tmp;
bool operator <(node x,node y){
return x.dis_sum>y.dis_sum;
}
bool v[maxn];
priority_queue <node> q;
void PusH(int dr,ll d){
tmp.drop=dr,tmp.dis_sum=d;
q.push(tmp);
}
void Dij(int s){
for(int i=1;i<=n;++i) dis[i]=INF,v[i]=false;
dis[s]=0;
PusH(s,0);
while(!q.empty()){
ll dis_sum=q.top().dis_sum;int x=q.top().drop;
q.pop();
if(v[x]) continue;
v[x]=true;
for(int i=head[x];i;i=edge[i].nxt){
int gr=edge[i].to;
if(dis[gr]>edge[i].dis+dis_sum){
dis[gr]=edge[i].dis+dis_sum;
PusH(gr,dis[gr]);
}
}
}
}
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i) doors[i]=INF;
for(int i=1;i<=m;++i){
int a,b;ll c;
scanf("%d%d%lld",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
for(int i=1;i<=k;++i) scanf("%d",&door[i]);
for(int i=1;i<=n;++i){
Dij(i);
if(i<n) foot[i]=dis[i+1];
for(int j=1;j<=k;++j)
doors[i]=min(doors[i],dis[door[j]]);
}
for(int i=1;i<n;++i) ans+=min(doors[i+1],foot[i]);
printf("%lld",ans);
return 0;
}
京公网安备 11010502036488号