问题 A: 分火腿
题目描述
小月⾔要过四岁⽣日了,她的妈妈为她准备了n根⽕腿,她想将这些⽕腿均分给m位小朋友,所以她可能需要切⽕腿。为了省事,小月⾔想切最少的⼑数,使这n根⽕腿分成均等的m份。请问最少要切⼏⼑?
输入
第⼀⾏⼀个整数T,表示有T组数据。
接下来T组数据,每组共⼀⾏,有两个数字n,m。
输出
每组数据⼀⾏,输出最少要切的⼑数。
样例输入 Copy
2
2 6
6 2
样例输出 Copy
4
0
思路:
一开始题目没说2根香肠分3份只要切2刀,wa了,后来考虑了这种情况,找规律可得解;
ll gcd(ll a,ll b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
int main()
{
int n;cin>>n;
while(n--)
{
ll x,y;
cin>>x>>y;
if(y==0||x%y==0) cout<<0<<endl;
else if(y%x==0)
{
ll z=y/gcd(x,y);
cout<<(z-1)*x<<endl;
}
else
cout<<y-gcd(x,y)<<endl;
}
return 0;
}
问题 B: 工资
题目描述
n+e在暑假参加了打零⼯的活动,这个活动分为n个⼯作日,每个⼯作日的⼯资为Vi。有m个结算⼯钱的时间,n+e可以自由安排这些时间,也就是说什么时候拿钱,老板说的不算,n+e才有发⾔权!(因为n+e是⼟豪,他是老板的老板)
n+e不喜欢身上⼀次性有太多的钱,于是他想安排⼀下拿钱的时间,使他⼀次性拿的钱中最⼤的那次的最小。(最后⼀天⼀定要领钱)
输入
第⼀⾏2个数n,m
接下来n⾏,每⾏⼀个数,代表Vi
输出
输出⼀⾏⼀个整数,表示最小的最⼤钱数。
样例输入 Copy
7 5
100
400
300
100
500
101
400
样例输出 Copy
500
提示
100 400//300 100//500//101//400// ”//” 表示 n+e 要去拿钱。
对于20%的数据,1<=n<=20
对于另20%的数据,1≤n≤50,Vi的和不超过1000
对于100%的数据,1≤n≤100000,m≤n,Vi≤100000
思路:
二分答案ans,判断mid是否符合judge函数的判断,符合判断则满足分组要求,可以将 r 减小,否则将 l 增大。
int n,m;
ll a[100005];///用long long
bool judge(ll mid)
{
int cnt=0;
ll ret=0;
for(int i=1;i<=n;i++)
{
if(ret+a[i]>mid)
{
ret=a[i];
cnt++;
}
else ret+=a[i];
if(cnt>=m || ret>mid)///有多于m个分组是大于mid的,则非法
return false; ///或者是其中一个数ret大于mid,也非法
}
if(cnt<m) return true;
return false;
}
int main()
{
cin>>n>>m;
ll ans,minn=1000000,maxn=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
maxn+=a[i];
minn=min(minn,a[i]);
}
while(minn<maxn)
{
ll mid=(minn+maxn)/2;
if(judge(mid)) maxn=mid;
else minn=mid+1;
}
cout<<minn<<endl;
}
问题 C: 公约数
题目描述
话说CD比较⽋扁,他表示在课室的日⼦没有教主在旁边打他的日⼦太寂寞了,所以这⼀晚,他终于来到了电脑室被打。由于CD是⼤家的宠物,于是⼤家都来打CD了。
电脑室里有n个⼈,第i个⼈希望打CD ai下。但是太多⼈打CD,他又会不爽,于是他规定只能有K个⼈打到他,并且为了公平起见,最终K个⼈打他的次数都必须是相同的,CD规定这个次数就是这K个⼈希望打他的次数的最⼤公约数。为什么是最⼤公约数呢?因为他觉得被打的次数是GCD的话他才会变成Glad CD。
之前说了,CD比较⽋扁,于是CD希望,K个⼈打他的次数的和最⼤。你能告诉他他最后总共会被打多少下么?
输入
第⼀⾏两个正整数n,k。
第⼆⾏n个正整数,表示每个⼈希望打CD多少下。
输出
输出⼀个正整数表示CD会被打多少下。
样例输入 Copy
3 1
1 2 3
样例输出 Copy
3
提示
对于30%的数据,保证k≤n≤20。
对于50%的数据,保证输⼊中所有数小于5000。
对于100%的数据,保证输⼊中所有数小于500000,k≤n。
思路:暴力枚举: i 从a[i]_max开始枚举到1,查询是否有大于等于k个数数是i的倍数,若有,则i是最大公约数。
int n;
ll k;
int visit[500005];
int main()
{
cin>>n>>k;
int maxn=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);visit[x]++;
maxn=max(maxn,x);
}
for(int i=maxn;i>=1;i--)
{
int cnt=0;
for(int j=i;j<=maxn;j+=i)///查询是否存在i的倍数
{
if(visit[j])cnt+=visit[j];///存在,则计算有多少个
if(cnt>=k) break;
}
if(cnt>=k)
{
printf("%lld",i*k);///cout会出错
break;
}
}
}