Gym 101205 (ACM-ICPC World Finals 2012)

来源:互联网 发布:淘宝哪个买家秀大尺度 编辑:程序博客网 时间:2024/03/29 07:06

PROBLEM B D ARE INCLUDED.

Problem B Curvy Little Bottles

题意:

         对一个瓶子标记刻度。瓶子被描述为:以 X 轴为中轴,切面为圆且圆的半径与X的关系式为 P

         第一行先给出 N 代表 表达式 P 的最高次幂。

         第二行给出 P 中 i 次幂的系数。

         第三行给出瓶底的 X 坐标 xlow,和瓶口的 X 坐标 xhigh,即要求每 V 单位容积需要标记刻度。

         请输出至多 8 个要标记刻度处离瓶底的距离。

思路:

         解题思路大致就是一道高数基础题,求旋转体的体积。

         由于多项式 P 并一定不是单调的且形状不定,我们不能直接二分求体积。

         需通过积分,求出 体积 与 X 的关系,再二分 X 。

代码:

代码精度控制很渣 eps开到-6才能过

#include <bits/stdc++.h>using namespace std;const double eps = 1e-6;const double PI = acos(-1);double a[12],f[22],F[25],low,high,v;int n;void integrate(){    memset(F,0,sizeof(F));    for(int i=1;i<=22;i++)        F[i]=f[i-1]/i;    return ;}double get_v(double x){    double ans=F[0];    double temp=x;    for(int i=1;i<=22;i++){        ans+=F[i]*temp;        temp*=x;    }    return PI*ans;}int main(){    int pppp=0;    while(scanf("%d",&n)!=-1){        for(int i=0;i<=n;i++)            scanf("%lf",&a[i]);        memset(f,0,sizeof(f));        for(int i=0;i<=n;i++)            for(int j=0;j<=n;j++)                f[i+j]+=a[i]*a[j];        integrate();        scanf("%lf%lf%lf",&low,&high,&v);        int cut=8;        double le,ri,mid=low,bot;        printf("Case %d: %.2lf\n",++pppp,get_v(high)-get_v(mid));        while(1){            if(!cut) break;            if(get_v(high)-get_v(mid)<v) break;            cut--;            if(cut!=7) printf(" ");            le=mid;            ri=high;            bot=mid;            while(le+eps<ri){                mid=(le+ri)/2;                if(get_v(mid)-get_v(bot)>v){                    ri=mid;                }else{                    le=mid;                }            }            printf("%.2lf",mid-low);        }        if(cut==8) printf("insufficient volume\n");        else printf("\n");    }}

Problem D Fibonacci Words

题意:

         题意如题图,给出一个斐波那契串,其构造方法为 str[0] = "0" str[1] = "1" F[i] = F[i-1] + F[i-2]

         问对于 str[N] (N<=100),其中包含几个模式串P,P的长度小于100000。

思路:

         其实是一个思维题。由于 str[100] 巨长,故不能暴力。

         当 str[i] 的长度较小时,我们可以直接 KMP 跑一边得到答案

         当 str[i] 的长度较大时

         考虑到 str[i] 的构造方式,对于某个串 P 的包含关系是继承的,继承的关系是:

                P[ str[i] ] = P[ str[i-1] ] + P[ str[i-2] ] + str[ i-1 ] 和 str[ i-2 ] 合并时产生的 P 串

         考虑到 P 的长度小于 100000 ,由于 str[i] 的构造方式, 当 str[i] 的长度大于 200000 时,以后的各个 str 拼接处的前 100000 个字符和后 100000 个字符将规律性重复。

       例:当 P长度为 2 时,假设 某个str[ x ] 为 11 ,str[ x+1 ] = 1110

             那么 str[ x+2 ] 为 11  10 + 11 (合并处10 和 11)

                     str[ x+3 ] 为 1110  11 +11  10 (合并处11 和 11)

                     str[ x+4 ] 为 11101111  10 + 11  1011 (合并处10 和 11)

                     str[ x+5 ] 为 11101111101110  11 + 11  10111110 (合并处11 和 11)

            每次合并处,偶次 和 奇次 合并产生重复。

          也就是说,当 str[i - 2] 的长度大于 200000 时,str[ i-1 ] 和 str[ i-2 ] 合并时产生的 P 串的数量是不变的,我们只要算出这两个数就可以。

代码:

#include <bits/stdc++.h>using namespace std;int nex[101000];long long num[105];void pre(string str){    int len=str.size();    nex[0]=-1;    int i=0,j=-1;    while(i<len){        if(j==-1||str[i]==str[j]){            i++;j++;            nex[i]=j;        }else            j=nex[j];    }}int kmp(string str1,string str2){    pre(str1);    long long ans=0;    int len1=str1.size(),len2=str2.size(),i=0,j=0;    while(i<len2&&j<len1){        if(j==-1||str1[j]==str2[i]){            i++;            j++;        }else            j=nex[j];        if(j==len1){            ans++;            j=nex[j];        }    }    return ans;}int main(){    string str[105];    int n;    str[1]="1";str[0]="0";    for(int i=2;i<=30;i++)        str[i]=str[i-1]+str[i-2];    string mark;    int cnt=0;    while(cin>>n>>mark){        cout<<"Case "<<++cnt<<": ";        if(n<=30){            cout<<kmp(mark,str[n])<<endl;        }else{            for(int i=27;i<=30;i++)                num[i]=kmp(mark,str[i]);            long long add1=num[30]-num[29]-num[28];            long long add2=num[29]-num[28]-num[27];            for(int i=31;i<=n;i++)                if(i%2) num[i]=num[i-1]+num[i-2]+add2;                else num[i]=num[i-1]+num[i-2]+add1;            cout<<num[n]<<endl;        }    }}





0 0
原创粉丝点击