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",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\n",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}=
\begin{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\n");
for(int i=1;i<=n-1;i++)
{
printf("1 ");
}
printf("%d\n",s-n+1);
printf("%d\n",s-n);
}
else
{
printf("NO\n");
}
}
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\n",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\n",min(f2(l),f2(r)));
}
}