A.Berland Poker
题意:给你一些卡牌分配给一些人,求分配后的人中最大卡牌数-第二大的卡牌数的最大值
题解:贪心,尽量全部给一个人,做不到的话多出来的平均分配给剩余的人,ceil printf要"%lf",不然会WA
#include
#include
#include
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int a=n/k;
if(m<=a)
printf("%d\n",m);
else
{
m-=a;
if(m/(k-1)==0)
cout<<a-1<<"\n";
else
cout<<a-ceil(1.0*m/(k-1))<<"\n";
}
}
return 0;
}
B. New Theatre Square
题意:有1x2和1x1的板砖可以让你铺地,1x2只能横着铺,各自花费cost1,cos2,铺的不能重叠,问铺完之后,花费最小值,
题解:水题,看看2*cos2和cost1的大小,如果前者小的话全部铺1x1,否则的话就模拟铺满2然后剩余用1填
#include
using namespace std;
typedef long long ll;
char s[105][1010];
int n,m,x,y;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&n,&m,&x,&y);
bool f=0;
for(int i=1;i<=n;++i)
scanf("%s",s[i]+1);
if(2*x>y)f=1;
int ans=0;
for(int i=1;i<=n;++i)
{
int k1=0;
int j=1;
while(j<=m)
{
k1=0;
while(s[i][j]!='.'&&j<=m)
j++;
while(s[i][j]=='.'&&j<=m)
{
j++;
k1++;
}
if(f)
{
ans=ans+k1/2*y;
k1=k1-k1/2*2;
ans=ans+x*k1;
}
else
{
ans=ans+k1*x;
k1=0;
}
continue;
}
}
printf("%d\n",ans);
}
return 0;
}
C.Mixing Water
题意:有冷热两种水,按照热冷热冷交替加入杯子,温度等于均值,给定指定的温度T,问最少的杯数使得 |tnow-T|最小
题解:其实真的是道水题,偶数杯温度显然就是**(a+b)/2**,奇数杯温度是**tnow=(n+1)/2n a+ (n-1)/2n b,懒得求函数的话,直接解开|tnow-T|=0的n最方便
答案一定就在n附近,枚举n附近的数取满足条件的最小的n,然后再和偶数比较,如果是偶数更小直接取2就好了,由于是小数会有偏差,一开始我取的是[n-1,n+1] WA了,后来改成[n-2,n+2]就A了,有点迷
#include
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
int main()
{
int k;
int a,b,t;
scanf("%d",&k);
while(k--)
{
scanf("%d%d%d",&a,&b,&t);
if(2*t==(a+b)&&a!=t){ //特判一下
puts("2");
continue;
}
int s=max(1,(a-b)/(2*t-(a+b)));
double ans=INF;
int num;
/* cout<
if(a==t){
puts("1");
continue;
}
else for(int i=s-2;i<=s+2;++i)
{
if(i%2==1)
{
double sum=fabs(t-(a+b)*1.0/2-1.0*(a-b)/2/i); //计算奇数绝对值差
if(ans>sum)
{
ans=sum;
num=i;
}
}
}
if((fabs(t-1.0*(a+b)/2)<ans)||(fabs(t-1.0*(a+b/2))==ans&&num>1))//偶数绝对值差
{
num=2;
}
printf("%d\n",num);
}
return 0;
}
D.Yet Another Yet Another Task
题意:找到一个区间使得区间总和-区间中最大元素的值最大
题意:一开始想用DP和线段树写(太傻叉了),其实-30<=ai<=30,我们只要枚举最大值i就好了,显然答案的下限是0,就是只取一个元素的时候,从左往右扫,cnt统计区间总和,当某个数大于最大值或者cnt<0时,当前区间断开,重新形成新区间计数,
该方法每次取的符合条件的区间必定是最优
下面证明:
假设符合条件的是[a,b]和[a-k,b-k],我们发现如果第二个区间更优,则[a,a-k-1]的cnt必须<0,反证[a,b]不符合,所以之前一定已经断开过,所以当前一定扫到的是最优的区间
假如当前的区间没有这个最大值的时候,可以发现一定存在小于这个最大值的数的答案更优,当前最大值无法更新,所以不会影响,这个方法可行,
#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
int cnt=0;
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
int ans=0;
for(int i=1;i<=30;++i)//枚举最大值
{
cnt=0;
for(int j=1;j<=n;++j)
{
if(a[j]>i)//区间断开
cnt=0;
else
{
cnt+=a[j];
if(cnt<0) //区间断开
cnt=0;
else
ans=max(ans,cnt-i);//不存在的最大值一定不会更新答案
}
}
}
printf("%d\n",ans);
return 0;
}
E.Modular Stability
题意:给你n和k,要求在[1, n]中找出不同的k个数,使得
其中1≤a1
题解:打表可得,当选定最小的a1时,剩余的数必须得是a1的倍数才可以满足,可以自己枚举a1=1,a1=2,a1=3试一下,就是在[p+1,n]中选k-1个a1的倍数的方案,
所以答案就是∑(i=1~n) C(n/i-1,k-1)
#include
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
const ll mod=998244353;
ll fac[maxn],inv[maxn];
int n,k;
ll mypow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(int i=2;i<=500005;++i)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=inv[i-1]*mypow(i,mod-2)%mod;
}
}
ll C(int n,int m)
{
if(n<0||m<0||n<m)return 0;
return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
init();
scanf("%d%d",&n,&k);
ll ans=0;
for(int i=1;i<=n;++i)
ans=(ans+C(n/i-1,k-1))%mod;//选定基数后,必须得是该基数的倍数才满足
printf("%lld\n",ans);
return 0;
}
F.RC Kaboom Show(待补)