Codeforces 458A (01串下黄金分割公式的拓展公式)

来源:互联网 发布:js substr slice 编辑:程序博客网 时间:2024/06/02 09:36

http://codeforces.com/contest/458/problem/A 题目地址

题目大意:

给两个01字符串,即字符串每个元素只能是0或1,长度不超过10^5,给定一个公式,val=a(0)*q^n+a(1)*q^(n-1)+...+a(n-1)*q^1+a(n);

其中q=(1+sqrt(5)) /2;  而a(n)表示串中的元素,0或1,问两个串哪个权值更大,或者一样?


题目还很好心的告诉了关于q这个黄金分割有关的公式,q^2=q+1,由此我们可以推出q^n=q^(n-1)+q^(n-2),这是一个类fibonacci数列,起始值又是大于1的。如果用简单粗暴的办法把权值求出来,是不可行的,fibonacci数列增长率和指数基本是一个级别的。那怎么办呢?


我们想到了浮点数高精度,我有朋友写出来但都wrong在text8,我不会浮点数高精度。难道就没有别的办法了吗?


其实仔细发现,这是一个dp递推题目。我们已经发现了q^n=q^(n-1)+q^(n-2)这个规律,又很高兴的知道字符串里只有0或1,所以只用考虑1的情况就好。

定义dp[i]表示 第i个位置 上串与下串的差值

比如

1000100

0010010

那么dp差值表示就是

10-101-10

1代表上串比下串大,0代表一样

为什么要这么做呢?因为我们发现了两个公式,这是根据等比数列求和而推出来的

公式一:q^n>q^0+q^1+q^2+...+q^(n-2)

公式二:2*q^n>q^0+q^1+q^2+...+q^(n-1)

证明略

那么,对于我们已经够建好的,用于表示上下两串差距的dp方程来说,我们从q^n处开始扫到q^0处,如果扫到0,则跳过

情况一:如果扫到1,并且下一个元素>=0,或者扫到了2,这个时候就分别可以通过两个公式说明上串大于下串了

情况二:如果扫到-1,并且下一个元素<=0,或者扫到了-2,情况类似,不叙述

情况三:如果扫到1,并且下一个元素<0,那么,通过q^n=q^(n-1)+q^(n-2),我们可以相当于把这个1减去,后面两个元素分别+1处理,再往下扫

情况四:如果扫到了-1,并且下一个元素>0,类似

但注意当i==1 或者 i==0时要特别判断


这样子,在扫一遍过后,我们就可以知道哪个串更大了。

注意构建dp的时候,我是将两个串均180转后填充'0',如果有更好方法,也可以,关键是那3个公式而推出的dp思想


代码如下:

说明:代码含有私人风格,如果发生歧义请原谅。并请尊重私人版权。

//Hello. I'm Peter.#include<cstdio>#include<iostream>#include<sstream>#include<iomanip>#include<cstring>#include<string>#include<cmath>#include<cstdlib>#include<algorithm>#include<functional>#include<cctype>#include<ctime>#include<stack>#include<queue>#include<deque>#include<vector>#include<set>#include<map>#include<limits>using namespace std;#define input freopen("data.txt","r",stdin)#define output freopen("output.txt","w",stdout)#define INT (0x3f3f3f3f)*2#define LL (0x3f3f3f3f3f3f3f3f)*2#define clr(a) memset(a,0,sizeof(a))#define clr_minus1(a) memset(a,-1,sizeof(a))#define clr_NULL(a) memset(a,NULL,sizeof(a))#define clr_INT(a) memset(a,INT,sizeof(a))#define clr_true(a) memset(a,true,sizeof(a))#define clr_false(a) memset(a,false,sizeof(a))#define clr_queue(q) while(!q.empty()) q.pop()#define clr_stack(s) while(!s.empty()) s.pop()#define rep(i, a, b) for (int i = a; i < b; i++)#define dep(i, a, b) for (int i = a; i > b; i--)#define repin(i, a, b) for (int i = a; i <= b; i++)#define depin(i, a, b) for (int i = a; i >= b; i--)#define ll long long#define eps#define MOD#define MAXN 200100#define N#define Mchar row1[MAXN];char row2[MAXN];int dp[MAXN];int d1,d2;int main(){    char t;    scanf("%s %s",row1,row2);    int len1=(int)strlen(row1);    int len2=(int)strlen(row2);    //将row1 180旋转    rep(i,0,len1/2)    {        t=row1[i];        row1[i]=row1[len1-i-1];        row1[len1-i-1]=t;    }    //将row2 180旋转    rep(i,0,len2/2)    {        t=row2[i];        row2[i]=row2[len2-i-1];        row2[len2-i-1]=t;    }    //填充‘0’,使两串元素个数一致    if(len1>len2)    {        rep(i,len2,len1)        {            row2[i]='0';        }        row2[len1]='\0';    }    else if(len1<len2)    {        rep(i,len1,len2)        {            row1[i]='0';        }        row1[len2]='\0';    }    int len=max(len1,len2);    //构建dp方程,代表上下两串的差别    rep(i,0,len)    {        d1=row1[i]-'0';        d2=row2[i]-'0';        dp[i]=d1-d2;    }    int first=0;    depin(i,len-1,0)    {        if(!dp[i]) continue;        //i==0和1时需要特判        if(i==0 || i==1)        {            if(dp[i]>0) first=1;            else if(dp[i]<0) first=-1;            else continue;            break;        }        //情况一 上串大        if((dp[i]>0 & dp[i-1]>=0) || dp[i]==2)        {            first=1;            break;        }        //情况二 下串大        else if((dp[i]<0 && dp[i-1]<=0) || dp[i]==-2)        {            first=-1;            break;        }        //情况三 需要调整        else if(dp[i]==1 && dp[i-1]<0)        {            dp[i]-=1;            dp[i-1]+=1;            dp[i-2]+=1;        }        //情况四 需要调整        else if(dp[i]==-1 && dp[i-1]>0)        {            dp[i]+=1;            dp[i-1]-=1;            dp[i-2]-=1;        }    }    //通过求出的first判断两串权值大小    if(!first) cout<<"="<<endl;    else if(first==1) cout<<">"<<endl;    else cout<<"<"<<endl;}

谢谢阅读。

0 0
原创粉丝点击