A:桶排取 \(max\)。
#include<bits/stdc++.h>
using namespace std;
#define Max(x,y)(x>y?x:y)
#define For(i,x,y)for(i=x;i<=y;i++)
int b[105];
int main()
{
int n,i,a,mx=0;
cin>>n;
For(i,1,n)cin>>a,b[a]++;
For(i,1,100)mx=Max(mx,b[i]);
cout<<mx;
return 0;
}
B:构造题。先间隔地放 0
1
\(x-1\) 次(多的先放,避免不够),然后放满最后放的哪一种,此时没有贡献,最后放另一种,贡献加一刚刚好。其实就是尽可能地先满足相邻两个不同的个数的条件。
#include<bits/stdc++.h>
using namespace std;
#define For(i,x,y)for(i=x;i<=y;i++)
int main()
{
int a,b,x,i,p,q;
cin>>a>>b>>x;
p=a;
q=b;
For(i,1,x)cout<<((i&1)==(a<b));
if(a>=b)b-=x>>1,a-=x-(x>>1);
else a-=x>>1,b-=x-(x>>1);
if((x&1)==(p>=q))
while(a--)putchar('0');
else
while(b--)putchar('1');
while(a>0)putchar('0'),a--;
while(b>0)putchar('1'),b--;
return 0;
}
C:\(n^2\) 暴力不多说。如果想要更优或更更优的解法请移步洛谷 P1404。
#include<bits/stdc++.h>
using namespace std;
#define Db double
#define Max(x,y)(x>y?x:y)
#define For(i,x,y)for(i=x;i<=y;i++)
int a[5005];
int main()
{
Db mx=0.0;
int n,k,i,sum,j;
cin>>n>>k;
For(i,1,n)cin>>a[i];
For(i,1,n-k+1)
{
sum=0;
For(j,i,i+k-2)sum+=a[j];
For(j,i+k-1,n)sum+=a[j],mx=Max(mx,Db(sum)/Db(j-i+1));
}
cout<<setiosflags(ios::fixed)<<setprecision(10)<<mx;
return 0;
}
D:将指数算出来,这样直接用数组存储。然后根据二的幂次优秀的性质(组合成任意正整数),从大到小去减,能减就减,最终没变成 \(0\) 就说明不可行。
#include<bits/stdc++.h>
using namespace std;
#define N 40
#define Min(x,y)(x<y?x:y)
#define For(i,x,y)for(i=x;i<=y;i++)
#define Memc(i,j)memcpy(i,j,sizeof i)
int tot[N],res[N];
int read()
{
int A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
void write(int X)
{
if(X<0)putchar('-'),X=-X;
if(X>9)write(X/10);
putchar(X%10|48);
}
int main()
{
int n,q,i,a,s,b,num,ret,k;
n=read(),q=read();
For(i,1,n)
{
a=read();
s=0;
while(a)s++,a>>=1;
tot[s]++;
}
while(q--)
{
a=b=read();
s=k=1;
num=0;
while(b>s)s<<=1,k++;
if(s>b)s>>=1,k--;
Memc(res,tot);
s=k;
while(s)
{
ret=Min(tot[s],b/(1<<(s-1)));
tot[s]-=ret;
b-=ret*(1<<(s-1));
num+=ret;
s--;
}
if(b)puts("-1");
else write(num),putchar('\n');
Memc(tot,res);
}
return 0;
}
E:还是构造题,要在有限的直径内尽可能地挂更多的点。随便选取一个根,考虑直径为偶数的情况,第一层是根结点,第二层是 \(k\) 个结点,第三层是 \(k\times(k-1)\) 个结点(上一层的结点有一个度数贡献给了上上层),第 \(i\) 层是 \(k\times(k-1)^{i-2}\) 个结点。这样一定最优,叶子结点到根结点的距离均是直径的一半,得到了充分的利用。
接着考虑奇数的情况,在偶数的情况上拓展。看一下第一层,在这里产生了 \(k\) 个分叉,也就是说,这 \(k\) 棵子树内各自的点之间的 lca 都不是根结点,而不同子树内的点之间的 lca 都是根结点。我们只能将直径加一,所以只能改变一棵子树内的叶子结点深度,如果改变两棵则直径会加二。那么让这棵子树内的叶子结点再长一层就行。
注意,这棵无向树的直径是由两棵不同子树内的叶子结点产生的。因为不同子树内叶子结点深度最多差 \(1\),若是同一棵子树内直径必定减少 \(2\)。
细节很多哦。
```cpp
include<bits/stdc++.h>
using namespace std;
typedef long long ll;
define For(i,x,y)for(i=x;i<=y;i++)
void write(int X)
{
if(X<0)putchar('-'),X=-X;
if(X>9)write(X/10);
putchar(X%10|48);
}
int main()
{
ll s=1,t;
int n,d,k,i,j,l;
cin>>n>>d>>k;
t=k;
if(d>=n)cout<<"NO",exit(0);
For(i,1,d>>1)
{
s+=t;
if(s>n)break;
t=(k-1);
}
if(d&1)s+=t/k;
if(s<n)cout<<"NO",exit(0);
puts("YES");
s=t=1;
n--;
i=0;
while(n)
{
For(j,s-t+1,s)
{
For(l,s+k(j-s+t-1)+1,s+k(j-s+t))
{
if(i+n==d)break;
if(j==s-t+t/(k+1)+1&&l==s+k(j-s+t-1)+1)i++;
if(j==s-t+1&&l==s+k(j-s+t-1)+1)i++;
n--;
write(j);
putchar(' ');
write(l);
putchar('\n');
if(!n)exit(0);
}
if(l<=s+k(j-s+t))break;
}
if(i+n==d)
{
while(n--)
{
write(l-1);
putchar(' ');
write(l);
putchar('\n');
l++;
}
exit(0);
}
t=k;
if(s==1)k--;
s+=t;
/cout<<s<<' '<<i<<endl;*/
}
return 0;
}