【LGR-148-Div.3】洛谷基础赛 #1 & MGOI Round I

发布时间 2023-08-06 18:35:10作者: LsmQwQ

T1

简单题,题面十分清晰,就是给我们\(n\),要求使\(2^m<n\)成立的最小偶数\(m\)。(要注意\(log_2N=m,m|2\)的情况)

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=800, INF=0x3f3f3f3f;
ll n; 
int main(){
	cin>>n;
	ll k=log(n)/log(2);
	if(k%2!=0)k=k-1;
	else if(pow(2,k)==n)k=k-2;
	cout<<k<<endl;
	return 0;
}

T2

有一点意思,很明显的模拟题,但是一定要细致。比如,第一次,我认为只需对于每一个客人,将他所想要的幕布和当前幕布放到函数判断即可(错误):

int f(char k,char want){
	if(k==want)return 0;
	if(k=='W'){
		if(want=='B')return 1;
		else return 2;
	}else if(k=='B'){
		if(want=='W')return 1;
		else return 1;
	}else if(k=='R'){
		if(want=='W')return 1;
		else return 1;
	}
}

但是,其实每一步操作,都存在所想要的幕布是否已经上升这一问题,上升与否是必须考虑的。稍加思索,发现可以将每一个幕布设成bool数组,为一则已经下降,为零则仍为上升。将目标幕布前的幕布值相加,在加上自身取反操作后的值(以为下降为一,而这时无需操作。为零时,反而需要操作)。

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=800, INF=0x3f3f3f3f;
int n;
bool f['Z'];//1 down;0 up
int ans=0;
int main(){
	cin>>n;
	f['R']=f['B']=f['W']=1;
	for(int i=1;i<=n;i++){
		char x;cin>>x;
		if(x=='W'){
			ans+=(!f['W']);
			f['W']=1;
		}
		if(x=='B'){
			ans+=f['W']+(!f['B']);
			f['W']=0;
			f['B']=1;
		}
		if(x=='R'){
			ans+=f['W']+f['B']+(!f['R']);
			f['W']=f['B']=0;
			f['R']=1;
		}
	}
	cout<<ans<<endl;
	return 0;
}

T3

一道图论题。不知道正解是什么(悲。想法为:正着模拟有点困难,因为无法确定当初的魔力值和生命,所以果断反向搜索。注意到求的是最小值,自然想到最短路。我们将每条边的权值变为走这条路的生命消耗值,然后跑一遍dijkstra即可。赛时,遇到若干问题:

  1. 我在build函数中已经改变了\(i.w\)的值,但是到dij函数就又回到原来的了(后来新建数组存储了)
  2. 内存爆炸,只能跑部分的\(n\)

后,注意到Sub3的特殊,解决。
30Pts代码:

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=2000+5, INF=0x3f3f3f3f;
ll n,m,s,t;
bool vis[N];
bool vis_edge[N][N];
struct node{
	ll v,w;
};
ll magic[N];
vector<node> G[N];
ll a[N][N];
void build(){
	queue<ll> Q;
	Q.push(t);
	magic[t]=1;
	while(Q.size()){
		ll x=Q.front();Q.pop();
		for(auto i:G[x]){
			if(!vis_edge[i.v][x]&&!vis_edge[x][i.v]){
				vis_edge[i.v][x]=1;
				vis_edge[x][i.v]=1;
				//cout<<x<<" To "<<i.v<<" from "<<i.w<<" to ";
				i.w=i.w/magic[x];
				a[i.v][x]=a[x][i.v]=i.w;
				//cout<<i.w<<endl;
				magic[i.v]=magic[x]+1;
				Q.push(i.v);
			}
		}
	}
}

struct Heapnode{
	ll v,dis;
	bool operator>(const Heapnode& a)const{return dis>a.dis;}
};
priority_queue<Heapnode,vector<Heapnode>,greater<Heapnode> > Q;
ll d[N];
void dij(ll nd){
	memset(vis,0,sizeof(vis));
	memset(d,INF,sizeof(d));
	Q.push({nd,0});
	d[nd]=0;
	while(Q.size()){
		ll u=Q.top().v;Q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto i:G[u]){
			ll x=i.v,y=a[u][x];
			if(!vis[x]&&d[u]+y<d[x]){
				d[x]=d[u]+y;
				Q.push({x,d[x]});
			}
		}
	}
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1;i<=m;i++){
		ll x,y,z;cin>>x>>y>>z;
		G[x].push_back({y,z});
		G[y].push_back({x,z});
	}
	if(n<=2000){
		build();
		/*for(int i=1;i<=n;i++){
			cout<<"第"<<i<<"个点:"<<endl;
			for(int j=1;j<=n;j++){
				cout<<"To "<<j<<" is "<<a[i][j]<<endl;
			}
		}*/
		dij(t);
		cout<<d[s]<<endl;
	}else{
		bool f=0;
		for(auto i:G[t])if(i.w==0){
			f=1;break;
		}
		if(f)cout<<0;
		else cout<<1;
	}
	return 0;
}

正解有人说DP。但是如果用bfs或者dij都需要考虑某点重复走路用生命值换取魔力值,从而走到更远的地方的情况。很明显,我没有考虑,很明显,不会了(等题解。

T4

题目清晰,不绕。Sub1明显是纯暴力分,用01来储存各个结点状态,然后模拟。中间剪了一些枝,但是无济于事。暴力分拿下,后面不会。

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=100+5, INF=0x3f3f3f3f;
int n,k;
int a[N];
bool zt[N];//1 激活;2 未激活 
/*bool pd(){
	int t=0;
	for(int i=1;i<=n;i++)if(zt[i])t++;
	return t>=k;
}*/
int minn=INF;
int Maxn(int x){
	bool fleft=0,fright=0;
	int m,dis,m2,dis2;
	
	for(int i=x;i>=1;i--){
		if(zt[i]){
			fleft=1;m=a[i];dis=x-i;break;
		}
	}
	if(!fleft){
		for(int i=n;i>=x;i--){
			if(zt[i]){
				m=a[i];dis=x+n-i;break;
			}
		}
	}
	
	for(int i=x;i<=n;i++){
		if(zt[i]){
			fright=1;m2=a[i];dis2=i-x;break;
		}
	}
	if(!fright){
		for(int i=1;i<=x;i++){
			if(zt[i]){
				m2=a[i];dis2=n-x+i;break;
			}
		}
	}
	
	if(m>m2)return m*dis;
	else return m2*dis2;
}
void f(int dep,int num1){
	if(num1+n-dep+1<k)return;
	if(dep>n){
		if(num1>=k){
			int ans=0;
			for(int i=1;i<=n;i++){
				if(zt[i])ans+=a[i]*a[i];
				else ans+=Maxn(i);
			}
			minn=min(minn,ans);
		}
		return ;
	}
	for(int i=0;i<=1;i++){
		zt[dep]=i;
		if(i==1)f(dep+1,num1+1);
		else f(dep+1,num1);
	}
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
	f(1,0);
	cout<<minn<<endl;
	return 0;
}

用时方面:
T1:6.82min
T2:34.67min
T3:2.37h
T4:2.98h
总分:100+100+30+13=243
rk:348
传送门