长沙网络赛G,H,J

最后时刻H因为几个代码细节问题导致没有通过,这场网络赛失败最大的责任恐怕就在我身上吧。。。。。另外G题比赛时没有明确的思路,耽误了不少时间。这样的表现只能用杯具来形容,感觉这场比赛坐下来,有些充满遗憾的感觉。。。。

G:

如何处理x+y+z = n呢?主要是一直感觉O(N^2)预处理会超时(后来竟然发现我机子太慢,同样的代码,在爱神的机子上运行<2s,在我的机子上就要运行3s+。。。)

后来队友也多次TLE,huyue学长又搞出神奇的东东。。。我就彻底撂下了,后来问了爱神,才知道原来可以n^2预处理是不会超时的。。。

首先要处理一个数可以拆成两个素数(可以允许相同)的解数,O(N^2)一下就好了。。。然后就是通过枚举第三个加数处理x+y+z的情况。复杂度O(n),但是有个问题,可能会重复计算。若x!=y!=z,则重复计算了三次。如果有两个数相等,则重复计算了两次,若x=y=z,则没有重复计算。那就统一变成重复计算三次吧。由于两个数相等的情况可以拆成x+2*y=n

统计一下这样的情况有多少就可以了。附代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
 
#define N 80005
#define cl(a) memset(a,0,sizeof(a))
#define ss(a) scanf("%d",&a)
#define pb push_back
#define ll long long
#define mod 1000000007

using namespace std;

ll ispri[N],add[N],mul[N];
vector<int>pri;
 
void prime()
{
    int i,j;
    for (i=2;i<N;i++)
        if (!ispri[i])
        {
            pri.pb(i);
            for (j=i*2;j<N;j+=i) ispri[j]=1;
        }
}



void init()
{
    int i,j;
    for (i=0;i<pri.size();i++)
        for (j=i;j<pri.size()&&pri[i]+pri[j]<N;j++)
        {
            add[pri[i]+pri[j]]++;
            if (pri[i]>=N/pri[j]) mul[pri[i]*pri[j]]++;    
        }
}                 

ll addmul(int n,int &rep)
{
    int i;
    ll re=0;
    for (i=0;i<pri.size()&&pri[i]<=n;i++) 
    {
        if ((n-pri[i])%2==0) 
        {
            rep++;
            if (pri[i]*3==n) rep++;
        }     
        re=(re+mul[n-pri[i]])%mod;
    }
    return re;
}

ll thmul(int n)
{
    int m=n,t=0,i=0;
    while (m>1)
    {
        while (n%pri[i]==0)
        {
            m/=pri[i];
            t++;
        }
        if (t>=3) break;
    }
    if (t==3&&m==1) return 1;
}

ll thadd(int n,int rep)
{
    int i;
    ll re=0;
    for (i=1;i<n-1;i++) re+=add[n-i];
    re=(re+rep)/3;
    return re%mod;
}

int main()
{
    prime();
    init();
    int n,rep;
    ll res=0;
    while (cin>>n)
    {
        if (!ispri[n]) res++;
        res=(res+mul[n]+add[n])%mod;
        rep=0;
        res=(res+addmul(n,rep)+thmul(n)+thadd(n,rep))%mod;
        cout<<res<<endl;
    }
    return 0;
}

最遗憾的H题

话说我连题都没看,YRC把公式告诉了我,问我这个公式(int)(l+sqrt(l*(l-1)))^k mod k

K太大,直接算不行,要做处理

刚开始我也没有想起来,后来觉得在学斐波那契序列转换为线性模式时碰到了带根号问题的处理,在纸上划了划,果然是这样

由于(l-sqrt(l*(l-1))^k<1,所以等价成(l+sqrt(l*(l-1))^k + (l-sqrt(l*(l-1))-1

前面的处理方式,组合数学有介绍斐波那契数列如何写成线性表达式的做法,省略,大概就是用到一元二次方程。。

推出了公式f(n) = 2*l*f(n) -l*f(n),并且模k

结果呢,矩阵快速幂写错了一点,另外取了k-1当模。。。。。。奇葩的代码。。。当然就杯具了。

这题要是当时AC了,就过关了。。

可是,现实就是这样,没有如果,你所做的只有努力去提升自己的实力,多敲代码。。。。改变自己代码风格上的不足来减少失误

#include <iostream>
#include <cstdio>

#define N 40
#define ll long long

ll a[N][3][3],f[3],mod;

using namespace std;

void init(ll l)
{
    a[0][1][1]=(2*l)%mod;a[0][1][2]=mod-l%mod;
    a[0][2][1]=1;a[0][2][2]=0;
    f[1]=2*l%mod;
    f[2]=2;
}

void rmul(ll x)
{
    int i,j,k;
    for (i=1;i<=2;i++)
        for (j=1;j<=2;j++)
        {
            ll res=0;
            for (k=1;k<=2;k++) res=(res+a[x-1][i][k]*a[x-1][k][j]%mod)%mod;
            a[x][i][j]=res; 
        }
}

void zmul(ll x)
{
    ll ff1=0,ff2=0;
    ff1=(f[1]*a[x][1][1]%mod+f[2]*a[x][1][2]%mod)%mod;
    ff2=(f[1]*a[x][2][1]%mod+f[2]*a[x][2][2]%mod)%mod;
    f[1]=ff1;
    f[2]=ff2;
}

void quick(ll k)
{
    //偏偏在这里写了mod=k,但这里的k是k-1啊。。。。 
    ll n=k,i=0;
    while (n>0)
    {
        if (n&1) zmul(i);
        i++;
        rmul(i);
        n>>=1; 
    }
}
  
int main()
{
    ll k,l;
    while (cin>>k>>l)
    {
        mod=k;    //刚开始我没有在这里对mod赋值 
        init(l);
        quick(k-1);
        cout<<(f[1]-1+mod)%mod<<endl;
    }
    return 0;
}

J

一道难度不大但不算水的题。。。赛后搞了一下,看完题后没思路。。后来看了题解,但没完全看(完全看就没意思了)。。果然后面的一些处理就真心乱套了

再加上读题时不够细致。。。。搞了好半天才AC

思路,由

bi = a[i-1]+a[i]+a[i+1]

b[i+1] = a[i] + a[i+1] +a[i+2]

因此可得 当a[i-1]已知,a[i+2]=b[i+1]-b[i]+a[i-1]

所以说,凡是a[3k+2]都可以推出,同理,a[n-3k+2]也可以推出

另一个结论,已知两个相邻的数可得到所有的数,或者已知第一个数,或最后一个数

这样的话,就是 XX0XX0XX0XX0....情况不知道,其中O代表可以推出的数

设a[0]=x,推出所有a[i]关于x的表达式,就a[i]>=0这个条件列出不等式,得到x的最小值和最大值

然后假设x=0,推出所有的a[i],根据a[i]的表达式,以及x取值范围,调整a[i]获得它们的最大值,附代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
    
#define ss(a) scanf("%d",&a)
#define N 100005
       
using namespace std;

int a[N],b[N],q[N];

void leftfind(int x)
{
    for (int i=x-2;i>=0;i--)
       a[i]=b[i+1]-a[i+1]-a[i+2];    
}

void rightfind(int x,int n)
{
    for (int i=x+1;i<n;i++)
        a[i]=b[i-1]-a[i-1]-a[i-2];
}

void printing(int m)
{
    for (int i=1;i<=m;i++) cout<<a[q[i]]<<endl;
}

int main()
{
    int n,i,m,flag,xmin,xmax,t;
    while (ss(n)!=EOF)
    {
        for (i=0;i<n;i++) ss(a[i]);
        for (i=0;i<n;i++) ss(b[i]);
        ss(m);
        flag=0;
        for (i=1;i<=m;i++) ss(q[i]);
        a[2]=b[1]-b[0];
        for (i=5;i<n;i+=3) a[i]=b[i-1]-b[i-2]+a[i-3];
        a[n-3]=b[n-2]-b[n-1];
        for (i=n-6;i>=0;i-=3) a[i]=b[i+1]-b[i+2]+a[i+3];
        for (i=1;i<n;i++)
        {
            if (a[i]!=-1&&a[i-1]!=-1) 
            {
                leftfind(i);
                rightfind(i,n);
                flag=1;
                break;
            }
        }
        if (a[0]!=-1&&!flag)
        {
            a[1]=b[0]-a[0];
            rightfind(2,n);
            flag=1;
        }
        if (a[n-1]!=-1&&!flag)
        {
            a[n-2]=b[n-1]-a[n-1];
            leftfind(n-2);
            flag=1;
        }
        if (flag) 
        {
            printing(m);
            continue;
        }
        t=0;xmin=0;xmax=100000;
        a[0]=0;
        for (i=1;i<n;i++)
        {
            if (i%3==1)
            {
                t=b[i-1]-t;
                xmax=min(xmax,t);
                a[i]=t;
            }
            else if (i%3==0)
            {
                t=b[i-1]-t;
                a[i]=t-a[i-1];
                xmin=max(xmin,a[i-1]-t);
            }
        }
        for (i=0;i<n;i++)
        {
            if (i%3==1) a[i]-=xmin;
            else if (i%3==0) a[i]+=xmax; 
        }
        printing(m);
    }    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值