LINK

操作 i i i灯,会改变所有 i i i约数的状态

如果灯是亮的,需要按偶数次,否则需要按奇数次。

随机按,如果当前局面小于 k k k次就能按完,就不随机,按照最优策略去按

问按照这样去按期望按多少次.


每个开关按多次相当于只按了奇数次或偶数次

我们可以从大到小扫一遍,因为最大的数一定是按自己才能改变

按了的话我们就可以去更新它的所有约数

这样就可以得到哪些键是一定要按的,其余键按了一次还需要多按一次调整回来

定义 f [ i ] f[i] f[i]表示 i i i个键需要按到 i − 1 i-1 i1个键需要按的期望次数

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+nni(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+inif[i+1]+ini=i(ni)+i+(ni)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 i1

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[ned1]...+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[i1]+nnif[i+1]+1

f [ i ] = f [ i − 1 ] + b [ i ] f[i]=f[i-1]+b[i] f[i]=f[i1]+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])+nni(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]=if[i]ib[i]+(ni)f[i]+(ni)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+(ni)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;
}