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;
}