ZJOI 2012 T1 数列

题目大意:已知一个数列:

 

数列

求它的第K项。

//=====================================================================================

直接按照题目给的条件DFS可拿30分左右,记忆化储存每个DFS到的Ai的数可以得到50分。再加高精度就可AC。

View Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
struct atp
{
    int len;
    int a[15];
    atp()
    {
        len=0;
        memset(a,0,sizeof(a));
        }
    }a,one;

struct Ha
{
    int next;
    pair<atp,atp> data;
    }h[15000];int first[40000],tot;

bool operator != (atp a,atp b)
{
    if (a.len!=b.len) return true;
    for (int i=1;i<=a.len;i++)
        if (a.a[i]!=b.a[i]) return true;
    return false;    
    }    

void insert(pair<atp,atp> a)
{
    int x=a.first.len*a.first.a[a.first.len]%39997;
    tot++;
    h[tot].data=a;
    h[tot].next=first[x];
    first[x]=tot;
    }

pair<bool,atp> Find(atp a)
{
    int x=a.len*a.a[a.len]%39997;
    if (first[x]==0) return pair<bool,atp>(false,a);
    x=first[x];
    while (x!=0 && h[x].data.first!=a) x=h[x].next;
    if (x==0) return pair<bool,atp>(false,a); else 
    return pair<bool,atp>(true,h[x].data.second);
    }

void print(atp a)
{
    printf("%d",a.a[a.len]);
    for (int i=a.len-1;i;i--)
    {
        if (a.a[i]<100000000)printf("0");
        if (a.a[i]<10000000)printf("0");
        if (a.a[i]<1000000)printf("0");
        if (a.a[i]<100000)printf("0");
        if (a.a[i]<10000)printf("0");
        if (a.a[i]<1000)printf("0");
        if (a.a[i]<100) printf("0");
        if (a.a[i]<10) printf("0");
        printf("%d",a.a[i]);
        }
    printf("\n");
    }
void init()
{
    int l,temp=0;
    char s[110];
    scanf("%s",s);
    l=strlen(s);
    a.len=l/9;
    temp=l%9;
    if (temp!=0) a.len++; else temp=9;
    for (int i=1;i<=temp;i++) a.a[a.len]=a.a[a.len]*10+s[i-1]-'0';
    for (int i=1;i<a.len;i++)
        for (int j=temp+(i-1)*9+1;j<=temp+(i-1)*9+9;j++) 
            a.a[a.len-i]=a.a[a.len-i]*10+s[j-1]-'0';
    }

atp Plus(atp a,atp b)
{
    atp c;
    int len=max(a.len,b.len);
    for (int i=1;i<=len;i++)
    {
        c.a[i]+=a.a[i]+b.a[i];
        c.a[i+1]+=c.a[i]/1000000000;
        c.a[i]%=1000000000;
        }
    if (c.a[len+1]!=0) len++;
    c.len=len;
    return c;
    }

void Div(const atp &a,int b,atp &c,int &d)
{
    int len;
    len=a.len;
    d=0;
    for(int i=len;i>=1;i--)
    {
       d=d*1000000000+a.a[i];
       c.a[i]=d/b;
       d%=b;
       }
    while(len>1&&c.a[len]==0) len--;
    c.len=len;
}



atp dfs(atp a)
{
    pair<bool,atp> p=Find(a);
    if (p.first) return p.second;
    atp c;int mod;
    Div(a,2,c,mod);
    if (mod==0) 
    {
        p=Find(c);
        if (p.first) return p.second; else
        {
            atp t=dfs(c);
            insert(pair<atp,atp>(c,t));
            return t;
            }
        } 
    atp t1,t2;
    p=Find(c);
    if (p.first) t1=p.second; else
    {
        t1=dfs(c);
        insert(pair<atp,atp>(c,t1));
        }
    p=Find(Plus(c,one));
    if (p.first) t2=p.second; else
    {
        t2=dfs(Plus(c,one));
        insert(pair<atp,atp>(Plus(c,one),t2));
        }
    return Plus(t1,t2);
    }

int main()
{
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    one.len=1;
    insert(pair<atp,atp>(one,one));
    one.a[1]=1;
    insert(pair<atp,atp>(one,one));
    int Case;
    scanf("%d",&Case);
    atp ans;
    while (Case--)
    {
        memset(a.a,0,sizeof(a.a));
        a.len=0;
        init();
        ans=dfs(a);
        print(ans);
        }
    return 0;
    }

 

 

 

一开始高精度压4位,TLE,5位还是TLE...最后改到6位才AC...我这个常数控制的是有多烂啊啊...WJMZBMR单位压得都比我快... Orz 之...

 

 

posted @ 2012-04-16 15:51  Evan1004  阅读(308)  评论(0编辑  收藏  举报