Problem A、锑集合
给读入的每一个
Ai
打上标记,然后判断任意
Ai+Aj
有没有被打上标记即可。
#include<cstdio>
#include<cstring>
int t,n,a[2000];
bool f[80000];
bool &at(int n){return f[n+30000];}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
memset(f,0,sizeof f);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)at(a[i]+a[j])=true;
bool ok=true;
for(int i=1;i<=n;i++)
if(at(a[i]))ok=false;
printf("%d\n",int(ok));
}
return 0;
}
Problem B、洪水
一道锻炼思维
的好题,有多种方法。
第一个解法:把所有格子按海拔顺序排序,把每一档海拔与下一档之间能够容纳的水依次累加直到大于水的总体积。
第二个解法:把所有格子按海拔顺序排序,逐个计算含水海拔,第n个格子的含水海拔=(总水量+n个格子相对于0海拔的体积)÷n个格子的面积和,顺序读入后面格子海拔,如果此格高于已算出的含水海拔则终止。
#include<cstdio>
#include<algorithm>
using namespace std;
int h[300000],n,m,cas=0;
double v,H,k;
int main()
{
scanf("%d%d",&n,&m);
n*=m;
for(int i=0;i<n;i++)scanf("%d",h+i);
h[n++]=2147483647;
sort(h,h+n);
scanf("%lf",&v);v/=100.0;
for(int i=1;i<=n;i++)
{
v+=h[i-1];H=v/i;
if(H<h[i]){k=i;break;}
}
printf("%.2f %.2f%%\n",H,100.0*k/(n-1));
return 0;
}
Problem C、最大公约数
我们先写个暴力程序搞出一些满足gcd(a,b)=a xor b=c的三元组(a,b,c),然后可以发现一个惊人的结论:c=a-b!
证明:不难发现a-b≤a xor b,且a-b≥c。假设存在c使得a-b>c,则c < a-b≤a xor b,与c=a xor b矛盾。
于是我们得出算法:枚举a和c,计算b=a-c,则gcd(a,b)=gcd(a,a-c)=c,所以只要验证是否存在c=a xor b即可,时间复杂度O(n log n)。
#include<cstdio>
int cnt[30000001],s[30000001],t,n;
int main()
{
for(int i=1;i<30000001;i++)
for(int j=i+i;j<30000001;j+=i)
if((j^(j-i))==i)cnt[j]++;
for(int i=1;i<30000001;i++)s[i]=s[i-1]+cnt[i];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%d\n",s[n]);
}
return 0;
}
Problem D、书架
不难想到用高度最小的书来填充第3层。
设f[i][j]表示第1、2层宽度分别为i、j时的最小总高度,
i=0:f[i+a[z].w][j]=min(f[i+a[z].w][j],f[i][j]+a[z].h)
i<>0:f[i+a[z].w][j]=min(f[i+a[z].w][j],f[i][j])
j=0:f[i][j+a[z].w]=min(f[i][j+a[z].w],f[i][j]+a[z].h)
j<>0:f[i][j+a[z].w]=min(f[i][j+a[z].w],f[i][j])
{z=1..n-1}
计算出f[][]然后就可以得出答案了。
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int f[3100][3100];
struct sh
{
int h,w;
}a[150];
bool cmp(sh a,sh b)
{
return a.h>b.h;
}
int main()
{
int n,i,j,z,t,w=0,s=0;
cin>>n;
for(i=0;i<n;i++) { cin>>a[i].h>>a[i].w;s+=a[i].w;}
sort(a,a+n,cmp);
memset(f,INF,sizeof(f));
f[0][0]=0;
for(z=1;z<n;z++)
for(i=s;i>=0;i--)
for(j=s;j>=0;j--)
if(f[i][j]!=INF)
{
if(i==0)
f[i+a[z].w][j]=min(f[i+a[z].w][j],f[i][j]+a[z].h);
else
f[i+a[z].w][j]=min(f[i+a[z].w][j],f[i][j]);
if(j==0)
f[i][j+a[z].w]=min(f[i][j+a[z].w],f[i][j]+a[z].h);
else
f[i][j+a[z].w]=min(f[i][j+a[z].w],f[i][j]);
}
t=INF;
for(i=1;i<=s;i++)
for(j=1;j<=s;j++)
if(f[i][j]!=INF)
{
w=max(i,j);
w=max(w,s-i-j);
t=min(t,(f[i][j]+a[0].h)*w);
}
cout<<t;
return 0;
}