膜你赛 2021.10.18

2021.10.18 膜你赛


T1

Description

由于小 X 是一个奆老,所以他看不起普通商店里卖的电子秤,他决定自己做一个。
他的称重工具是一架由金子制成的天平, 这架天平的精度非常高, 可以达到纳克的标准,
1g=10 9 ng,小 X 会把物品放在天平的右侧,然后在天平的左侧和右侧都放上一些砝码,直至
天平平衡。该天平的砝码是用钻石制成的,每个砝码的质量依次为 1ng、3ng、9ng、27ng、
81ng……,每个砝码的质量都是 3 的幂次(如 3 的 6 次幂表示为 3^6=729),且各不相同。
由于小 X 是一个奆老,他有对各个物品未卜先知的能力,他会告诉你他的物品的质量,
希望你给他一个方案,使得天平的两侧平衡。

Solution

对于给出的 W,进行三进制拆分,如果这一位是 1,砝码加在左边,如果当前是 2,砝码加在右边,并进位。

Code

/*
* @Author: smyslenny
* @Date:    2021.10.
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>

#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=1e9+7;
const int M=1e3+5;
int n;
int read()
{
    int x=0,y=1;
    char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    return y?x:-x;
}
int tre[M],num,fg;
int ans_l[M],ans_r[M],js_l,js_r=1;
bool check(int x)
{
	return x==n;
}
namespace substack1{
	void dfs(int pos)
	{
		if(fg) return;
		if(check(num)) 
		{
			fg=1;
			for(int i=1;i<=js_l;i++) printf("%lld ",ans_l[i]);
			printf("\n%lld ",n);
			for(int i=1;i<=js_r;i++) printf("%lld ",ans_r[i]); 
			printf("\n");
			return;
		}
		if(pos>10) return;
		ans_l[++js_l]=tre[pos];
		num+=tre[pos];
		dfs(pos+1);
		num-=tre[pos]*2;
		js_l--;
		ans_r[++js_r]=tre[pos];
		dfs(pos+1);
		num+=tre[pos];
		js_r--;
		dfs(pos+1);
	}	
	void main()
	{
		dfs(0);
	}
}
namespace substack2{
	void dfs(int pos)
	{
		if(fg) return;
		if(check(num)) 
		{
			fg=1;
			for(int i=1;i<=js_l;i++) printf("%lld ",ans_l[i]);
			printf("\n%lld ",n);
			for(int i=1;i<=js_r;i++) printf("%lld ",ans_r[i]); 
			printf("\n");
			return;
		}
		if(pos>10) return;
		ans_l[++js_l]=tre[pos];
		num+=tre[pos];
		dfs(pos+1);
		num-=tre[pos]*2;
		js_l--;
		ans_r[++js_r]=tre[pos];
		dfs(pos+1);
		num+=tre[pos];
		js_r--;
		dfs(pos+1);
	}	
	void main()
	{
		dfs(0);
	}
}
namespace substack3{
	int tri[M],cnt,sz[M],zs[M],m,mm;
	void main()
	{
		int W=n,s=1;
		while(W)
		{
			tri[++cnt]=W%3;
			W/=3;
		}
		for(int i=1;i<=cnt+1;i++)
		{
			if(tri[i]==1)
			{
				if(sz[mm]==s)
					sz[mm]=s*3,zs[++m]=s;
				else sz[++mm]=s;
			}
			if(tri[i]==2)
			{
				if(sz[mm]==s)
					sz[mm]=s*3;
				else zs[++m]=s,sz[++mm]=s*3;
			}
			s*=3;
		}
//		printf("%d ",sz[1]);
		for(int i=1;i<=mm;i++) printf("%lld ",sz[i]);
		printf("\n%lld ",n);
		for(int i=1;i<=m;i++) printf("%lld ",zs[i]);
	}
}
signed main()
{
//	freopen("entertain.in","r",stdin);
//	freopen("entertain.out","w",stdout);
	n=read();
//	tre[0]=1;
//	for(int i=1;i<=50;i++) tre[i]=tre[i-1]*3;
//	js_l=0,js_r=0;
//	if(n<=10000) substack1::main();
//	else substack2::main(); 
	substack3::main();
	return 0;
}
		 

T2

Description

小 S 和小 Z 十分喜欢看网络写手“2 5 ”的小说,但由于需要付费才能阅读,而小 S 和小
Z 的零花钱有非常少,他们只能找小 X 靠黑科技侵入给网站,把小说给他们。
然而小 X 又非常的爱慕虚荣,他要小 S 和小 Z 到自己家里来取小说。
小 S、小 Z 和小 X 都居住在扬中市,扬中市共有 n 个小区,m 条主干道(假设每条主干
道都是双行线)。小 S 家住在 1 号小区,小 X 家住在 n 号小区。小 S 每经过一条主干道需要
耗费 z 点体力,但由于小 S 的人脉非常广,每当他到达一个小区,他都会和好友攀谈直到体
力回满。
由于小 Z 也希望能看到小说,所以他答应帮助小 S k 次,这 k 次小 S 经过主干道不需要
耗费体力。
由于小 S 生性懒惰,他希望耗费最少的体力到达小 X 家,请问他最少耗费多少体力?
注意:如果小 S 到小 X 家可以一路上都由小 Z 背着,那么体力上限为 0;
如果小 S 到不了小 X 家,小 S 会很伤心,体力上限为-1;

Solution

二分一个最大值,最短路check 一下。
由于数据不是很强,也可以跑分层图。

Code

/*
* @Author: smyslenny
* @Date:    2021.10.
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>

#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=1e9+7;
const int M=1e4+5;
int n,m,k,Ans=-1;
int read()
{
    int x=0,y=1;
    char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    return y?x:-x;
}
struct ed{
	int u,v,w,net;
}edge[M<<1];
int head[M],num;
void addedge(int u,int v,int w)
{
	edge[++num].u=u;
	edge[num].v=v;
	edge[num].w=w;
	edge[num].net=head[u];
	head[u]=num;
}

struct node{
	int u,dis;
	bool operator < (const node &a) const {
		return dis>a.dis;
	}
};
priority_queue<node> q;
int dis[M],vis[M];
int check(int mid)
{
	memset(dis,INF,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[1]=0; 
	q.push(node{1,dis[1]});
	while(!q.empty())
	{
		node x=q.top();
		q.pop();
		int u=x.u;
		vis[u]=1;
		for(int i=head[u];i;i=edge[i].net)
		{
			int v=edge[i].v,w=edge[i].w,dist=dis[u];
			if(vis[v]) continue;
			if(w>=mid) dist++;
			if(dis[v]>dist)
			{
				dis[v]=dist;
				q.push(node{v,dis[v]});
			}
		}
	}
	return dis[n]>=k+1;
}

int main()
{
	freopen("novel.in","r",stdin);
	freopen("novel.out","w",stdout);
	n=read(),m=read(),k=read();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read(),w=read();
		addedge(u,v,w);
		addedge(v,u,w);
	}
	int l=0,r=1e6+100;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
			l=mid+1,Ans=mid;
		else r=mid-1;
	}
	if(Ans>1e6) printf("-1\n");
	else if(r<0) printf("0\n");
	else printf("%d\n",Ans);
	return 0;
}

T3

Description

他准备给两位奆老中的一个人绿叶配红花,另一个人红叶配绿花。
由于绿叶配红花大家说顺口了, 所以小 X 家楼下的花店里就有出售, 但红叶配绿花是小
X 口味独特的体现,花店里当然是不会有的,小 X 只能自行拼凑。
他家种了一棵枫树,现在有的枫叶是红色的,有的枫叶是黄色的,小 X 只要采摘红色的
枫叶。每片枫叶有一个年轻程度,他希望他采摘的枫叶的年轻程度总和越小越好。
这棵枫树有 n 个节点(从 0 开始编号),m 片叶子。他希望采摘到恰好 k 片红色叶子的
经过每个节点的年轻程度总和最小的生成树。
注意:保证数据有解。

Solution

wqs二分的板子题,当时我竟然没想到!

Code

/*
* @Author: smyslenny
* @Date:    2021.10.
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>

#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=1e9+7;
const int M=5e4+5;
int n,m,k,js,Ans;
int read()
{
    int x=0,y=1;
    char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    return y?x:-x;
}

int du[M],f[M],tot,cnt;
int find(int x)
{
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
struct ed{
	int u,v,w,col;
}edge[M<<1],e[M<<1];

bool cmp(ed a,ed b)
{
	if(a.w==b.w) return a.col<b.col;
	return a.w<b.w;
}

bool check(int mid)
{
	tot=cnt=0;
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++)
	{
		e[i]=edge[i];
		if(edge[i].col==0) e[i].w+=mid;
	}
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;i++)
	{
		int fa=find(e[i].u),fb=find(e[i].v);
		if(fa!=fb)
		{
			f[fa]=fb;
			tot+=e[i].w;
			if(!e[i].col) cnt++;
		}
	}
	return cnt>=k;
}
// 
int main()
{
//	freopen("leaf.in","r",stdin);
//	freopen("leaf.out","w",stdout); 
	n=read(),m=read(),k=read();
	for(int i=1;i<=m;i++)
		edge[i].u=read()+1,edge[i].v=read()+1,edge[i].w=read(),edge[i].col=read();
	int l=-105,r=105;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
			l=mid+1,Ans=tot-k*mid;//减去我们二分的附加值 
		else r=mid-1;
	}
	printf("%d\n",Ans);
	return 0;
}
上一篇:[cf1599G]Shortest path


下一篇:10.14训练赛