CF1309总结

A

这道题比较简单,必定会出现0的情况,判断一下,之后的操作都不用做了

16min打完B回来才想到方法A了

#include <iostream>
#include <cstring>

using namespace std;

long long t,n,k;

long long check(long long now)
{
  int max=11,min=-1;
  for(;now;now/=10)
  {
    if(now%10>max) max=now%10;
    if(now%10<min) min=now%10;
  }
  return max*min;
}

int main()
{
  scanf("%lld",&t);
  while(t--)
  {
    scanf("%lld%lld",&n,&k);
    for(int i=2;check(n);i++)
    {
      n+=check(n);
    }
    printf("%lld
",n);
  }
}

B

有点恶心,考试的时候没加快读被卡了,真的烦

贪心一下就好了,每一个属性的人先和自己相同的组队,如果有组队剩下的,就降维打击,留给后面的匹配(

(ans)统计一下就ok,复杂度(O(n))

#include <iostream>
#include <cstring>

#pragma GCC optimize(2)
#pragma GCC optimize(3)

using namespace std;

int t,n,a[300005],ans;

inline int read()
{
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}

int main()
{
  t=read();
  while(t--)
  {
    ans=0;
    n=read();
    memset(a,0,4*(n+1));
    for(int i=1;i<=n;i++)
    {
      int now=read();
      a[now]++;
    }
    for(int i=1;i<=n;i++)
    {
      if(a[i])
      {
        ans+=a[i]/i;
        a[i+1]+=a[i]%i;
      }
    }
    printf("%d
",ans);
  }
}

C

先枚举一条边(我选择的是y)

然后分情况判断,复杂度(O(n))

#include <iostream>
#include <cstdio>

using namespace std;

long long ans=0,a,b,c,d,x,y,z,now;

int main()
{
  cin>>a>>b>>c>>d;
  for(long long i=a;i<=b;++i)
  {
    y=i+b;
    if(y>c)
    {
      if(y>d)
      {
        ans+=(c-b+1)*(d-c+1);
        continue;
      }
      z=y+c-b;
      if(z>d)
      {
        now=z-d;
        ans+=now*(d-c+1);
        ans+=((y-c)+(d-c))*(d-y+1)/2;
      }
      else ans+=((y-c)+(z-c))*(z-y+1)/2;
    }
    else
    {
      z=y+c-b;
      if(z<=c) continue;
      if(z>d)
      {
        now=z-d;
        ans+=now*(d-c+1);
        ans+=(1+(d-c))*(d-c)/2;
      }
      else ans+=(1+(z-c))*(z-c)/2;
    }
  }
  cout<<ans;
}

D

贪心一下,一眼看去没思路

但是你如果会鸽巢原理的话

就会想到构建一个这样的数列:

[a_{i}= egin{cases} 1 & 1 leq i leq n-1 \ s-n+1 & i=n end{cases} ]

然后判断条件,看看(n)(s-n+1)的关系

至于为啥No,可以考虑一下同样用鸽巢原理(我也说不清楚

#include <iostream>

using namespace std;

int n,s;

int main()
{
  scanf("%d%d",&n,&s);
  if(s-n+1>n)
  {
    printf("Yes
");
    for(int i=1;i<=n-1;i++)
    {
      printf("1 ");
    }
    printf("%d
",s-n+1);
    printf("%d
",s-n);
  }
  else
  {
    printf("NO
");
  }
}

E

三分

首先考虑一下(m)这个东西,首先就看看是否(m>a+r)

大于显然(m)就没用了,直接考虑(a)(r)的就行了,小于的时候就分开就好

至于为啥是单峰,我也不知道啊,只是感觉一个增减性(

#include <cstdio>
#include <iostream>

using namespace std;

long long n,a,r,m;

long long c[1000010];

long long minn,maxn;

long long f(long long now)
{
  long long ans=0;
  for(int i=1;i<=n;i++)
  {
    if(c[i]>now)
    {
      ans+=(c[i]-now)*r;
    }
    else
    {
      ans+=(now-c[i])*a;
    }
  }
  return ans;
}

long long f2(long long now)
{
  long long up=0,down=0;
  for(int i=1;i<=n;i++)
  {
    if(c[i]>now)
    {
      up+=(c[i]-now);
    }
    else
    {
      down+=(now-c[i]);
    }
  }
  if(up>down)
  {
    return (up-down)*r+down*m;
  }
  else
  {
    return (down-up)*a+up*m;
  }
}

int main()
{
  scanf("%lld%lld%lld%lld",&n,&a,&r,&m);
  for(int i=1;i<=n;i++)
  {
    scanf("%lld",&c[i]);
    minn=min(minn,c[i]);
    maxn=max(maxn,c[i]);
  }
  if(m>=a+r)
  {
    long long l=minn,r=maxn;
    while(r>l)
    {
      long long m1=(2*l+r)/3,m2=(2*r+l+2)/3;
      if(f(m1)<f(m2)) r=m2-1;
      else l=m1+1;
    }
    printf("%lld
",min(f(l),f(r)));
  }
  else
  {
    long long l=minn,r=maxn;
    while(r>l)
    {
      long long m1=(2*l+r)/3,m2=(2*r+l+2)/3;
      if(f2(m1)<f2(m2)) r=m2-1;
      else l=m1+1;
    }
    printf("%lld
",min(f2(l),f2(r)));
  }
}

原文地址:https://www.cnblogs.com/zzqdeco/p/12904072.html