T1:Berry Picking
T2:Loan Repayment
T3:Wormhole Sort
还是USACO的题,全是奶牛……
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
排序,以 %后的结果来排序
不断平均分,累加后找最大值
#include
#include
#include
#include
#include
#include
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);
}
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
输出最大的正整数 X,使得按照上述过程 Farmer John 会给 Bessie 至少 N 加仑牛奶。
10 3 3
2
二分,必须的
需要考虑优化二分,最好一次性算出很多天的还奶量,后半部分就是除法,主函数就是二分
最后输出左端点
#include
#include
#include
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;
}
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,输出
#include
#include
#include
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;
}