您的位置:首页 > 其它

Bestcoder round#33 解题报告

2016-05-20 00:26 197 查看

1001

简单的进制转换问题。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;
char p[36];
int a[310];
char s[310];
int n,b,l;
int main()
{
for (int i=0;i<=9;i++)
p[i]=(char)(i+'0');
for (int i=10;i<36;i++)
p[i]=(char)(i-10+'a');
while (scanf("%d %d",&n,&b)==2)
{
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++)
{
scanf("%s",s);
l=strlen(s);
int pos=0;
for (int j=l-1;j>=0;j--)
{
int d;
if (s[j]>='0'&&s[j]<='9') d=s[j]-'0';
else d=s[j]-'a'+10;
a[pos++]+=d;
}
}
int flag=0;
for (int i=0;i<=220;i++)
{
a[i]%=b;
if (a[i]) flag=i;
}
for (int i=flag;i>=0;i--)
printf("%c",p[a[i]]);
printf("\n");
}
return 0;
}


1002

我们所选取的a[i]一定是整个序列中最大或者最小的,这两种情况完全等价。不妨考虑a[i]是最大数这种情况:选出a[i]后,剩下有n-1个数,对于每个数都有两种放法,放在a[i]左侧或者放在a[i]右侧,一共2n−1种。如果每个数放左还是放右已经确定了,那么显然整个序列也就确定了。那么总方案数应该为2n种。但是会有重复:a[i]最大,且左边没有数,和a[i]最小,且右边没有数;a[i]最大,且右边没有数,和a[i]最小,且左边没有数。所以ans应该为2n−2 。但是我们需要注意特判n=1的情况,此时答案应该为1 。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
LL p;
LL n;
LL multi(LL a, LL b)
{
LL ret=0;
while(b)
{
if(b&1) ret=(ret+a)%p;
a=(a+a)%p;
b>>=1;
}
return ret;
}
LL pow_mod(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1) ret=multi(ret,a)%p;
a=multi(a,a)%p;
b>>=1;
}
return ret;
}

int main()
{
while (cin>>n>>p)
{
if (n==1) cout<<1%p<<endl;
else
{
LL ans=pow_mod(2,n)-2;
while (ans<0) ans+=p;
cout<<ans<<endl;
}
}
return 0;
}


1003

简单的背包问题,不过注意物品的选取顺序有讲究。我们需要按照l[i]-t[i]的大小,从小到大进行排序(满足拓扑序),之后就跟最简单的01背包完全一致了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
LL f[1100000];
int l[40],v[40],t[40],b[40],a[40];
int cmp(int x,int y)
{
return b[x]<b[y];
}
int n,w,maxx,tt;
int main()
{
while (scanf("%d %d",&n,&w)==2)
{
memset(f,0,sizeof(f));
maxx=tt=0;
for (int i=1;i<=n;i++)
{
scanf("%d %d %d",&t[i],&v[i],&l[i]);
a[i]=i;
maxx=max(maxx,l[i]);
tt+=t[i];
b[i]=l[i]-t[i];
}
tt+=maxx;
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++)
{
int ll=max(t[a[i]],l[a[i]]);
for (int j=tt;j>=ll;j--)
{
f[j]=max(f[j],f[j-t[a[i]]]+(LL)v[a[i]]);
}
}
int flag=0;
for (int i=1;i<=tt;i++)
{
if (f[i]>=w)
{
flag=1;
printf("%d\n",i);
break;
}
}
if (!flag) printf("zhx is naive!\n");
}
return 0;
}


1004

很容易想到二分,设答案为ans。那么我们需要判断是否存在一组wb,hb,wg,hg,满足wb∗hb+wg∗hgwb+wg≥ans,即

ans∗wb−wb∗hb+ans∗wg−wg∗hg≤0

显然此时我们是要维护斜率,由于询问是在树上的一个简单路径。所以我们需要将树树链剖分,然后在每个线段树上建凸包,在凸包内二分。思路很简单,但是由于太弱,还没调试成功,为了打卡,先把题解放在这里,等以后过了,再把代码贴上来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: