Educational Codeforces Round 88 (Rated for Div. 2) A-E

A.Berland Poker
题意:给你一些卡牌分配给一些人,求分配后的人中最大卡牌数-第二大的卡牌数的最大值

题解:贪心,尽量全部给一个人,做不到的话多出来的平均分配给剩余的人,ceil printf要"%lf",不然会WA

#include<iostream>
#include<cstdio>
#include<cmath> 

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<bits/stdc++.h>

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<bits/stdc++.h>

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<<s<<"\n";*/ 
       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<bits/stdc++.h>

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<a2<⋯<ak≤n 1≤a1<a2<⋯<ak≤n1≤a1<a2<⋯<ak≤n,x>=0 x>=0x>=0

题解:打表可得,当选定最小的a1时,剩余的数必须得是a1的倍数才可以满足,可以自己枚举a1=1,a1=2,a1=3试一下,就是在[p+1,n]中选k-1个a1的倍数的方案,
所以答案就是∑(i=1~n) C(n/i-1,k-1)

#include<bits/stdc++.h>

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(待补)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值