【紀中2020.4.11日】模擬賽題解

目錄:

T1:Berry Picking
T2:Loan Repayment
T3:Wormhole Sort

還是USACO的題,全是奶牛🐄……

正題:

T1:Berry Picking

題目描述

Bessie 和她的妹妹 Elsie 正在 Farmer John 的漿果園裏採漿果。Farmer John 的漿果園裏有 N 棵漿果樹(1≤N≤1000);樹 i 上有 Bi 個漿果(1≤Bi≤1000)。Bessie 有 K 個籃子(1≤K≤1000,K 爲偶數)。每個籃子裏可以裝同一棵樹上採下的任意多個漿果,但是不能裝來自於不同的樹上的漿果,因爲它們的口味可能不同。籃子裏也可以不裝漿果。
Bessie 想要使得她得到的漿果數量最大。但是,Farmer John 希望 Bessie 與她的妹妹一同分享,所以 Bessie 必須將漿果數量較多的 K/2 個籃子給 Elsie。這表示 Elsie 很有可能最後比 Bessie 得到更多的漿果,這十分不公平,然而姐妹之間往往就是這樣。
幫助 Bessie 求出她最多可以得到的漿果數量。

輸入

輸入的第一行包含空格分隔的整數 N 和 K。
第二行包含 N 個空格分隔的整數 B1,B2,…,BN。

輸出

輸出一行,包含所求的答案。

樣例輸入

5 4
3 6 8 4 2

樣例輸出

8

分析:

排序,以 %後的結果來排序
不斷平均分,累加後找最大值

CODE:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
using namespace std;
int n,k,a[1001],maxn,f,ans,t,b;
bool cmp(int x,int y)
{
    return x%t>y%t;  //以%後來排序
}
int main(){
	freopen("berries.in","r",stdin);
	freopen("berries.out","w",stdout);
	scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        maxn=max(maxn,a[i]);  //找出最大值
    }
    for(int i=1;i<=maxn;i++)
    {
        f=0;
        for(int j=1;j<=n;j++)
            f+=a[j]/i;  //平均分
        if(f<(k/2))  //特判無用功
            break;
        if(f>=k)  //特判
        {
            ans=max(ans,i*(k/2));  //分一次
            continue;
        }
        t=i;
        sort(a+1,a+n+1,cmp);  //%後排序
        b=(f-k/2)*t;  //一開始的值
        for(int x=1;x<=n,x+f<=k;x++)
            b+=a[x]%t;  //累加,%
        ans=max(ans,b);  //找最大值
    }
    printf("%d",ans);
}

T2:Loan Repayment

題目描述

Farmer John 欠了 Bessie N 加侖牛奶(1≤N≤10^12)。他必須在 K 天內將牛奶給 Bessie。但是,他不想將牛奶太早拿出手。另一方面,他不得不在還債上有所進展,所以他必須每天給 Bessie 至少 M 加侖牛奶(1≤M≤10^12)。
以下是 Farmer John 決定償還 Bessie 的方式。首先他選擇一個正整數 X。然後他每天都重複以下過程:
(1)假設 Farmer John 已經給了 Bessie G 加侖,計算 (N−G)/X 向下取整。令這個數爲 Y。
(2)如果 Y 小於 M,令 Y 等於 M。
(3)給 Bessie Y 加侖牛奶。
求 X 的最大值,使得 Farmer John 按照上述過程能夠在 K 天后給 Bessie 至少 N 加侖牛奶 (1≤K≤10^12)。

輸入

輸入僅有一行,包含三個空格分隔的正整數 N、K 和 M,滿足 K⋅M<N。
注意這個問題涉及到的整數規模需要使用 64 位整數類型(例如,C/C++ 中的“long long”)。

輸出

輸出最大的正整數 X,使得按照上述過程 Farmer John 會給 Bessie 至少 N 加侖牛奶。

樣例輸入

10 3 3

樣例輸出

2

分析:

二分,必須的
需要考慮優化二分,最好一次性算出很多天的還奶量,後半部分就是除法主函數就是二分
最後輸出左端點

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,k,m;
bool check(long long x)
{
	long long z=k,y=n; //y爲剩餘天數
	while(1)
	{
		long long f,p;
		f=y/x;
		if(f<m) return m*z>=y;  //處理第二部分
		p=y/f-x+1;
		if(p>z) p=z;  //天數要在範圍內
		y-=p*f;
		z-=p;
		if(y<=0) return 1;
		if(z==0) return 0;
	}
}
int main()
{
    freopen("loan.in","r",stdin);
    freopen("loan.out","w",stdout);
    cin>>n>>k>>m;
    long long l=1,r=n,mid;
    while(l<r)
    {
    	mid=(l+r+1)/2;  //二分邊界注意+1
    	if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout<<l;
    return 0;
}

T3:Wormhole Sort

題目描述

Farmer John 的奶牛們已經厭倦了他對她們每天早上排好序離開牛棚的要求。她們剛剛完成了量子物理學的博士學位,準備將這一過程搞快點。
今天早上,如同往常一樣,Farmer John 的 N 頭編號爲 1…N 的奶牛(1≤N≤10^5),分散在牛棚中 N 個編號爲 1…N 的不同位置,奶牛 i 位於位置 pi。但是今天早上還出現了 M 個編號爲 1…M 的蟲洞(1≤M≤10^5),其中蟲洞 i 雙向連接了位置 ai 和 bi,寬度爲 wi(1≤ai,bi≤N,ai≠bi,1≤wi≤10^9)。
在任何時刻,兩頭位於一個蟲洞兩端的奶牛可以選擇通過蟲洞交換位置。奶牛們需要反覆進行這樣的交換,直到對於 1≤i≤N,奶牛 i 位於位置 i。
奶牛們不想被蟲洞擠壞。幫助她們最大化被她們用來排序的蟲洞寬度的最小值。保證奶牛們有可能排好序。

輸入

輸入的第一行包含兩個整數 N 和 M。
第二行包含 N 個整數 p1,p2,…,pN。保證 p 是 1…N 的一個排列。
對於 1 到 M 之間的每一個 i,第 i+2 行包含整數 ai、bi 和 wi。

輸出

輸出一個整數,爲在排序過程中奶牛必須擠進的蟲洞的最小寬度的最大值。如果奶牛們不需要用任何蟲洞來排序,輸出 −1。

樣例輸入

4 4
3 2 1 4
1 2 9
1 3 7
2 3 10
2 4 3

樣例輸出

9

分析:

這道題爲並查集
判斷如果可以走就並在一起
完後做記錄,將值賦給ans,輸出

CODE:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
    int x,y,z;
}a[100001];
int n,m,p[100001],sum=0,f[100001],ans;
bool cmp(node a1,node b1){
	return a1.z>b1.z;  //排序
}
int find(int x){
	return f[x]==x?x:f[x]=find(f[x]);  //就是getfather函數
}
int main()
{
	freopen("wormsort.in","r",stdin);
	freopen("wormsort.out","w",stdout);
    scanf("%d%d",&n,&m);
    bool flag=1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&p[i]);
        f[i]=i;  //記錄
        if(p[i]!=i) flag=0,sum++;
    }
    if(flag)
    {
        printf("-1"); //直接特判不合法
        return 0;
    }
    for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+1+m,cmp);  //輸入後排序
    for(int i=1;i<=m;i++)
    {
        int fx=find(a[i].x),fy=find(a[i].y);  //分別找祖先
        if(fx!=fy) 
        {
            if(p[a[i].x]!=a[i].x||p[a[i].y]!=a[i].y)  f[fx]=fy,ans=a[i].z;  //判斷能否並,然後賦值
        }
    }
    printf("%d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章