[Shoi2017]分手是祝愿

Posted yyys-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Shoi2017]分手是祝愿相关的知识,希望对你有一定的参考价值。

传送门

分析得知:

每个开关最多按一次,且最优一定是从后往前按(因为对约数有影响,前面的无法再影响到后面大的)

那么可以先处理出至少需要按几次“正确”的开关(从后往前保证都是按的正确的)

有一半的数据满足 k=n,或者k大于正确按的次数,这个时候与期望无关,直接从后往前按就行。

然后考虑到与期望有关的。

期望步数与是否按到正确开关有关。

设f[i]为从还需要按i次开关到还需要按i-1次开关的期望步数。

技术图片

有i/n的概率这一步按到正确开关,(n-i)/n的概率按到错误开关。

如果按到错误开关,在之后的操作中需要将这个开关按回来,所以就多了一次--->f[i+1],按回来后,还要按i次才能到i-1次--->f[i],加上本身这一次的1。

式子化简一下技术图片

技术图片
#include<bits/stdc++.h>
#define LL long long
#define N 100003
#define mod 100003
using namespace std;
int read()

    int x=0,f=1;char s=getchar();
    while(s<0||s>9)if(s==-)f=-1;s=getchar();
    while(s>=0&&s<=9)x=x*10+s-0;s=getchar();
    return x*f;

void print(int x)

    if(x<0)putchar(-);x=-x;
    if(x>9)print(x/10);
    putchar(x%10+0);

int now[N];
LL f[N];
LL quick(LL a,LL x)

    LL ans=1;
    while(x)
    
        if(x&1)ans=ans*a%mod;
        a=a*a%mod;x>>=1;
    
    return ans;

int main()

    freopen("trennen.in","r",stdin);
    freopen("trennen.out","w",stdout);
    int n=read(),k=read();
    for(int i=1;i<=n;++i)now[i]=read();
    LL cnt=0;
    for(int i=n;i>=1;--i)
      if(now[i])
      
          cnt++;
          for(int j=1;j*j<=i;++j)
            if(i%j==0)
            
              now[j]^=1;
              if(j*j!=i)now[i/j]^=1;
          
      
    if(cnt<=k)
    
        for(int i=2;i<=n;++i)
          cnt=cnt*i%mod;
        printf("%lld\\n",cnt);    
        return 0;
    
    f[n+1]=0;
    for(int i=n;i>k;--i)//从n推,最多按n次开关,从cnt开始推的话,可能一开始按错了很多步而f没有这种状态 
      f[i]=((n+(n-i)*f[i+1]%mod))%mod*quick(i,mod-2)%mod;
    LL ans=k;
    for(int i=k+1;i<=cnt;++i)
      ans=(ans+f[i])%mod;
    for(int i=2;i<=n;++i)
      ans=ans*i%mod;
    printf("%lld\\n",ans);
 
View Code

 

以上是关于[Shoi2017]分手是祝愿的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4872: [Shoi2017]分手是祝愿

[Shoi2017]分手是祝愿

LOJ #2145. 「SHOI2017」分手是祝愿

loj2145 「SHOI2017」分手是祝愿

bzoj 4872 [Shoi2017]分手是祝愿

bzoj 4872: [Shoi2017]分手是祝愿