操作 i i i灯,会改变所有 i i i约数的状态
如果灯是亮的,需要按偶数次,否则需要按奇数次。
随机按,如果当前局面小于 k k k次就能按完,就不随机,按照最优策略去按
问按照这样去按期望按多少次.
每个开关按多次相当于只按了奇数次或偶数次
我们可以从大到小扫一遍,因为最大的数一定是按自己才能改变
按了的话我们就可以去更新它的所有约数
这样就可以得到哪些键是一定要按的,其余键按了一次还需要多按一次调整回来
定义 f [ i ] f[i] f[i]表示 i i i个键需要按到 i − 1 i-1 i−1个键需要按的期望次数
f [ i ] = i n + n − i n ( f [ i + 1 ] + f [ i ] + 1 ) f[i]=\frac{i}{n}+\frac{n-i}{n}(f[i+1]+f[i]+1) f[i]=ni+nn−i(f[i+1]+f[i]+1)
化简得到 f [ i ] = 1 + n − i i f [ i + 1 ] + n − i i = ( n − i ) + i + ( n − i ) f [ i + 1 ] i f[i]=1+\frac{n-i}{i}f[i+1]+\frac{n-i}{i}=\frac{(n-i)+i+(n-i)f[i+1]}{i} f[i]=1+in−if[i+1]+in−i=i(n−i)+i+(n−i)f[i+1]
意思是如果按对了直接对了,概率是 i n \frac{i}{n} ni
如果按错了,变成有 i + 1 i+1 i+1个键需要按,花费 f [ i + 1 ] f[i+1] f[i+1]按到 i i i再花费 f [ i ] f[i] f[i]按到 i − 1 i-1 i−1
设 n e d ned ned是初始需要按的个数
这样 f [ n e d ] + f [ n e d − 1 ] . . . + f [ k + 1 ] + k f[ned]+f[ned-1]...+f[k+1]+k f[ned]+f[ned−1]...+f[k+1]+k就是答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 100003;
const int maxn = 3e5+10;
int n,k,a[maxn],f[maxn];
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1,x=x*x%mod )
if( n&1 ) ans = ans*x%mod;
return ans;
}
signed main()
{
cin >> n >> k;
for(int i=1;i<=n;i++) cin >> a[i];
int ned = 0;
for(int i=n;i>=1;i--)
{
if( a[i]%2==0 ) continue;
ned++;
for(int j=1;j*j<=i;j++)
{
if( i%j!=0 ) continue;
a[j] ^= 1;
if( j*j!=i ) a[i/j] ^= 1;
}
}
for(int i=n;i>=1;i--)
{
int inv = quick( i,mod-2 )*(n-i)%mod;
f[i] = (1+inv*f[i+1]+inv )%mod;
}
int ans = k;
if( ned<=k ) ans = ned;
else
{
for(int i=ned;i>=k+1;i--) ans = ( ans+f[i] )%mod;
}
for(int i=1;i<=n;i++) ans = ans*i%mod;
cout << ans;
}
那么定义 f [ i ] f[i] f[i]表示还剩 i i i个关键键没按,按完的期望
当 i ∈ [ 1 , k ] i\in[1,k] i∈[1,k]时, f [ i ] = i f[i]=i f[i]=i,否则
f [ i ] = i n f [ i − 1 ] + n − i n ∗ f [ i + 1 ] + 1 f[i]=\frac{i}{n}f[i-1]+\frac{n-i}{n}*f[i+1]+1 f[i]=nif[i−1]+nn−i∗f[i+1]+1
设 f [ i ] = f [ i − 1 ] + b [ i ] f[i]=f[i-1]+b[i] f[i]=f[i−1]+b[i]
代入得到 f [ i ] = i n ( f [ i ] − b [ i ] ) + n − i n ∗ ( f [ i ] + b [ i + 1 ] ) + 1 f[i]=\frac{i}{n}(f[i]-b[i])+\frac{n-i}{n}*(f[i]+b[i+1])+1 f[i]=ni(f[i]−b[i])+nn−i∗(f[i]+b[i+1])+1
n f [ i ] = i ∗ f [ i ] − i b [ i ] + ( n − i ) f [ i ] + ( n − i ) b [ i + 1 ] + n nf[i]=i*f[i]-ib[i]+(n-i)f[i]+(n-i)b[i+1]+n nf[i]=i∗f[i]−ib[i]+(n−i)f[i]+(n−i)b[i+1]+n
化简得到 b [ i ] = n + ( n − i ) b [ i + 1 ] i b[i]=\frac{n+(n-i)b[i+1]}{i} b[i]=in+(n−i)b[i+1]
边界 b [ n ] = 1 b[n]=1 b[n]=1
递推 b b b,然后递推 f f f即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 100003;
const int maxn = 3e5+10;
int n,k,a[maxn],f[maxn],b[maxn];
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1,x=x*x%mod )
if( n&1 ) ans = ans*x%mod;
return ans;
}
signed main()
{
cin >> n >> k;
for(int i=1;i<=n;i++) cin >> a[i];
int ned = 0;
for(int i=n;i>=1;i--)
{
if( a[i]%2==0 ) continue;
ned++;
for(int j=1;j*j<=i;j++)
{
if( i%j!=0 ) continue;
a[j] ^= 1;
if( j*j!=i ) a[i/j] ^= 1;
}
}
int ans = 0;
if( ned<=k ) ans = ned;
else
{
b[n] = 1;
for(int i=n-1;i>=1;i--) b[i] = ( n+(n-i)*b[i+1] )%mod*quick(i,mod-2)%mod;
f[k] = k;
for(int i=k+1;i<=ned;i++) f[i] = ( f[i-1]+b[i] )%mod;
ans = f[ned];
}
for(int i=1;i<=n;i++) ans = ans*i%mod;
cout << ans;
}