ICPC乌鲁木齐赛后感悟

最后一次比赛了,虽然打铁了,但是并不可惜,三人都尽了全力,坚持到了比赛的最后一刻,每个人都在为了这个团队付出,这才是比赛的意义所在。

2017新疆乌鲁木齐icpc题目偏向数学,稳铜的4题都是数学题。

B和G是两个签到题,看手速。

D题正解是推出一个组合数的式子,我们用的是矩阵快速幂(全场过这题的估计没几个用这个的)。队友找的是三层的递推关系,我构造了6*6的矩阵,一切顺风顺水敲出了代码,但是前期一直TLE,最后半小时走投无路瞎改,竟然改对了???

把指数取模直接过了???不符合数学常理啊,应该是数据水(不这么解释有些颠覆世界观啊)。

K题一直没明白队友说的题意和他的思路,自己看了一会儿理解透题意后立马反应到最后结果是对一个n,小于n的并且与n互质的数的平方和。那么可能是有素数分解和容斥的,前些天刚做过两三道这样的题,立马有了思路。由于我准备的比较充分,1^2+2^2+3^2+……+n^2的公式直接记了,素数分解的过程也想清楚了,容斥的二进制枚举的过程也想清楚了(后来发了官方题解发现和我的思路一模一样),敲上去之后一直提示一个好像是浮点错误的消息,直接出不了结果(这实在是太打击人了,明明是把一个数素数分解,这个数整除任意个素因子累积,结果必然是一个整数,就算不是整数,两个long long 类型的碰到/运算符也是整除的意思,怎么会莫名其妙出现浮点数错误呢?),最后这题让队友调试他的直接暴力的代码了,一直T到最后,无果。

最终结果是过了三题,后来在飞机上想了想我的容斥的方法,确实是一点毛病也没有,而且符合ICPC的基本考点,还好打印了一个版本的代码,赛后调了不一会儿就出数了,代码如下,等待验证其正确性。

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
int MOD=998244353;
LL Stack[1000],top,Cnt[1000],tmp[1000];
void fenjie(LL k)
{
    top=0;
    memset(Cnt,0,sizeof(Cnt));
    for(LL i=2;i*i<=k;i++)if(k%i==0)
    {
        while(k%i==0)Cnt[top]++,k/=i;
        Stack[top++]=i;
    }
    if(k>1)
    {
        Cnt[top]++;
        Stack[top++]=k;
    }
}
LL quick(LL m,LL n)
{
    LL b=1;
    while(n>0)
    {
        if(n&1)b=(b*m)%MOD;
        n=n>>1;
        m=(m*m)%MOD;
    }
    return b;
}
LL f(LL n)
{
    LL ans=(((n*(n+1))%MOD)*(((2*n)%MOD+1)%MOD))%MOD;//cout<<"a="<<ans;
    ans=(ans*quick(6,MOD-2))%MOD;//cout<<"  b="<<ans<<endl;
    return ans;
}
LL solve(LL a)
{
    LL ans1=0;
    for(LL i=1;i<(1<<top);i++)
    {
        LL sum=0,ans=1;
        for(LL j=0;j<top;j++)
            if(i&(1<<j))
        {
            sum++;
        ans=(ans*Stack[j])%MOD;
        }
        if(sum&1)
            ans1=(ans1+((f(a/ans)*ans)%MOD*ans)%MOD)%MOD;
        else
            ans1=(ans1-((f(a/ans)*ans)%MOD*ans)%MOD+MOD)%MOD;
    }
    return ans1;
}
int main()
{
    int t;
    LL n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        fenjie(n);
        /*for(LL i=0;i<top;i++)
            cout<<Stack[i]<<" ";
        cout<<endl<<endl;

        for(LL i=0;i<top;i++)
            cout<<Cnt[i]<<" ";
        cout<<endl;*/
        LL anss=f(n);
        LL ass=solve(n);//cout<<anss<<" "<<ass<<" ";
        anss=((anss-ass)+MOD)%MOD;
        printf("%lld\n",anss);
    }
    return 0;
}


  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值