bzoj 1002 轮状病毒 打表

一眼看到数据范围,输入只有1个n,n<100果断打表。然而好像跑表的复杂度不兹磁啊,要跑几年。所以要打表找规律。

#include<iostream>//这是小数据打表
#include<cstdio>
using namespace std;
struct E{int f,t;}b[100005];
int cnt,n;
int use[100005];
int fa[100005];
int find(int x)
{return fa[x]==x?x:fa[x]=find(fa[x]);}
int ans;
void dfs(int x,int k)
{
    if(k==n)
    {
        for(int i=0;i<=n;i++)
            fa[i]=i;
        bool h=1;
        for(int i=1;i<=k;i++)
        {
            int p=use[i];
            int x=b[p].f,y=b[p].t;
            if(find(x)!=find(y))
                fa[find(x)]=find(y);
            else {h=0;break;}
        }
        if(h) ans++;
        return ;
    }
    if(x>cnt) return ;
    use[k+1]=x;
    dfs(x+1,k+1);
    dfs(x+1,k);
}
int main()
{
    for(n=1;n<=100;n++)
    {
        ans=0;cnt=0;
        for(int i=1;i<n;i++)
            b[++cnt]=(E){i,i+1};
        b[++cnt]=(E){n,1};
        for(int i=1;i<=n;i++)
            b[++cnt]=(E){0,i};
        dfs(1,0);cout<<n<<" "<<ans<<endl;
    }
}
/*
1 1
2 5
3 16
4 45
5 121
6 320
7 841
8 2205
9 5776
10 15125
11 39601
12 103680
13 271441
14 710645
15 1860496
16 4870845
17 12752041
18 33385280
*/

我打出n<=17的答案,想起在某学堂讲过自动找规律机,但我当时在颓废,于是硬生生的用眼瞪出了规律,合理猜想,大胆假设。对于奇数,答案都是某个数c【i】的平方。c[i]=c[i-2]*3-c[i-4];
对于偶数,答案是某个数c[i]除以5,c[i]=c[i-2]*7-c[i-4]+2;
然后是高精度。

#include<iostream>
#include<cstdio>
using namespace std;
struct Big
{
    int a[10005];
    int x;
    void print()
    {
        bool pr=0;
        for(int i=x+100;i>=1;i--)
            if(a[i]||pr)printf("%d",a[i]),pr=1;
    }
    void pre()
    {
        for(int i=1;;i++)
        {
            if(i>x&&a[i]==0)
            {
                x=i-1;
                break;
            }
            if(a[i]>9)
            {
                a[i+1]+=a[i]/10;
                a[i]%=10;
            }
        }
    }
}f[105];
Big operator *(Big A,int b)
{
    int x=A.x;
    for(int i=1;i<=x;i++)
        A.a[i]*=b;
    A.pre();
    return A;
}
Big zero;
Big operator *(Big A,Big B)
{
    Big C=zero;
    for(int i=1;i<=A.x;i++)
    for(int j=1;j<=B.x;j++)
        C.a[i+j-1]+=A.a[i]*B.a[j];
    C.x=A.x+B.x;
    C.pre();
    return C;
}
Big operator -(Big A,Big B)
{
    for(int i=1;i<=A.x;i++)
    {
        A.a[i]-=B.a[i];
        if(A.a[i]<0)
        {
            A.a[i+1]--;
            A.a[i]+=10;
        }
    }int x=0;
    for(int i=A.x;i>=1;i--)
    {
        if(A.a[i])
        {
            x=i;
            break;
        }
    }
    A.x=x;
    return A;
}
int main()
{
    int n;
    scanf("%d",&n);
    f[1].a[1]=1;f[3].a[1]=4;
    f[2].a[1]=1;f[4].a[1]=9;
    for(int i=1;i<=4;i++)
        f[i].x=1;
    if(n%2)
    {
        for(int i=5;i<=n;i+=2)
            f[i]=f[i-2]*3-f[i-4];
        f[n]=f[n]*f[n];
        f[n].print();
    }
    else
    {
        for(int i=6;i<=n;i+=2)
        {
            f[i]=f[i-2]*7-f[i-4];
            f[i].a[1]+=2;
            f[i].pre();
        }
        f[n]=f[n]*5;
        f[n].print();
    }
    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值