您的位置:首页 > 其它

8月10号的练习:ZOJ 3203&&POJ 3974&&HDU 1394&&HDU 3400&&HDU 2152

2013-08-12 00:14 483 查看
Light Bulb ZOJ 3203

又是一道数学题:(三分法)

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
double H,h,D,l,r,mid,mmid;
int n;
scanf("%d",&n);
while(n--)
{
scanf("%lf%lf%lf",&H,&h,&D);
l=(H-h)*D/H;
r=D;mid=0;mmid=0;
while(r-l>1e-9)
{
mid=(l+r)/2;
mmid=(mid+r)/2;
if((mid+(H-h)*D/mid)>(mmid+(H-h)*D/mmid))
l=mid;
else if((mid+(H-h)*D/mid)<(mmid+(H-h)*D/mmid))
r=mmid;
else
break;
}
printf("%.3lf\n",D+H-(l+(H-h)*D/l));
}
return 0;
}


貌似不能二分角度!没有图不好说,具体参见:/article/2142175.html(里面有数学解法)

Palindrome POJ 3974

一道求最长回文子串:(必须是连续的)

就是用什么Manacher算法:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
using namespace std;
char a[1000005],b[2000005];
int d[2000005];
int main()
{
int n,i,mia,ip,max1,d1=0;
while(scanf("%s",a)!=EOF)
{
if(a[0]=='E')
break;
n=strlen(a);
b[0]='@';
b[1]='#';
for(i=0;i<n;i++)
{
b[i*2+2]=a[i];
b[i*2+3]='#';
}
b[2*n+2]='\0';
n=2*n+2;
mia=0;
ip=0;
max1=1;
for(i=0;i<n;i++)
{
if(mia>i)
d[i]=min(d[2*ip-i],mia-i);
else
d[i]=1;
for(;b[i-d[i]]==b[i+d[i]];d[i]++)
if(i+d[i]>mia)
{
mia=i+d[i];
ip=i;
}
max1=max(max1,d[i]);
}
printf("Case %d: %d\n",++d1,max1-1);
}
return 0;
}


该算法的基本思路:

先是把原字符串扩大两倍:每隔一个插上‘#’,听说可以避免奇偶性的讨论。

之后还有一个剪枝问题:具体参见:http://www.2cto.com/kf/201210/164253.html

Minimum Inversion Number HDU 1394

一道线段树的问题,可以暴力也可树状数组:(由于精力有限,只用了线段数)

还是逆序数的问题:(这道不用离散化)

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct line
{
int left;
int right;
int ma;
}a[5005];
void build(int left,int right,int root)
{
a[root].left=left;
a[root].right=right;
a[root].ma=0;
if(left==right)
return ;
build(left,(left+right)/2,2*root);
build((left+right)/2+1,right,2*root+1);
}
void insert1(int x,int root)
{
if(x<a[root].left||x>a[root].right)
return ;
if(x==a[root].left&&x==a[root].right)
{
a[root].ma++;return ;
}
if(x>=a[root].left&&x<=a[root].right)
a[root].ma++;
insert1(x,2*root);
insert1(x,2*root+1);
}
int find1(int left,int right,int root)
{
if(a[root].left>=left&&a[root].right<=right)
return a[root].ma;
if(a[root].left>right||left>a[root].right)
return 0;
return (find1(left,right,2*root)+find1(left,right,2*root+1));
}
int main()
{
int sum,min1,n,i;
int a1[5005];
while(scanf("%d",&n)!=EOF)
{
build(1,n,1);
sum=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a1[i]);
a1[i]++;
insert1(a1[i],1);
sum+=find1(a1[i]+1,n,1);//需要边更新,边求值
}
min1=sum;
for(i=1;i<=n-1;i++)
{
sum-=a1[i]-1;
sum+=n-a1[i];//题目求的是最小值,每次把第一个数移到最后的最小值(逆序数的变化很明显)
if(sum<min1)
min1=sum;
}
printf("%d\n",min1);
}
return 0;
}


要得出答案主要是利用了一个结论:如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少y[i],而增加n-1-y[i]的。(可以这样想,因为是第一个数,所有的数都在它后面,那么在当前位置pos比它大的数也在它后面,那么第一个数调到后面之后,在pos不成立的逆序数就成立了,所以多了n-y[i]-1,但是也少了在pos成立的逆序数,即y[i]个)

Line belt HDU 3400

三分题:(要进行两次三分求解)

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct point
{
double x,y;
};
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double p,q,r;
double find2(point a,point c,point d)
{
point left,right;
point mid,midmid;
double t1,t2;
left=c;
right=d;
do
{
mid.x=(left.x+right.x)/2;
mid.y=(left.y+right.y)/2;
midmid.x=(mid.x+right.x)/2;
midmid.y=(mid.y+right.y)/2;
t1=dis(a,mid)/r+dis(mid,d)/q;
t2=dis(a,midmid)/r+dis(midmid,d)/q;
if(t1>t2)
left=mid;
else
right=midmid;
}while(dis(left,right)>=1e-9);
return t1;
}
double find(point a,point b,point c,point d)
{
point left,right;
point mid,midmid;
double t1,t2;
left=a;
right=b;
do
{
mid.x=(left.x+right.x)/2;
mid.y=(left.y+right.y)/2;
midmid.x=(mid.x+right.x)/2;
midmid.y=(mid.y+right.y)/2;
t1=dis(a,mid)/p+find2(mid,c,d);
t2=dis(a,midmid)/p+find2(midmid,c,d);
if(t1>t2)
left=mid;
else
right=midmid;
}while(dis(left,right)>=1e-9);
return t1;
}
int main()
{
int T;
point a,b,c,d;
scanf("%d",&T);
while(T--)
{
scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
scanf("%lf%lf%lf%lf",&c.x,&c.y,&d.x,&d.y);
scanf("%lf%lf%lf",&p,&q,&r);
printf("%.2lf\n",find(a,b,c,d));
}
return 0;
}


之后是到母函数:可以说是模板题了。

Fruit HDU 2152

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int main()
{
int a[105],b[105];
int c1[10005],c2[10005];
int n,m,i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d%d",&a[i],&b[i]);
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
c1[0]=1;
for(i=1;i<=n;i++)
{
for(j=0;j<=m;j++)
for(k=a[i];k<=m&&k<=b[i];k++)
c2[k+j]+=c1[j];
for(j=0;j<=m;j++)
{
c1[j]=c2[j];
c2[j]=0;
}
}
printf("%d\n",c1[m]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: