题解 分手是祝愿

whca!!!

题目传送门

Description

(n) 盏初始状态为 (a_{1,2,...,n}) 的灯,在修改一个灯的状态时它的所有因子都会跟着修改,每次随机修改一个点的状态,在把剩余灯都关掉的最小操作次数 (le k) 的时候会直接采用最优方案。问期望操作次数乘上 (n!)

(nle 10^5)

Solution

可以(bu neng) 想到的是,一个灯的影响不能通过其它灯组合(不包含该灯)来实现,也就是说一定是有些灯是必须要按的(或者说叫按奇数次),我们设有 (s) 个这种灯,而其它的灯按了之后必须按回来。

那我们就可以设计状态 (f_i) 表示现在有 (i) 盏需要按的灯,把需要按的灯的数量从 (i) 变为 (i-1) 的期望操作次数。可以得到转移式:

[f_i=frac{i}{n}+frac{n-i}{n} imes (f_{i+1}+f_i+1) ]

(frac{i}{n}) 表示直接按到需要按的灯上去了,(frac{n-i}{n}) 意义则相反,(f_{i+1}+f_{i}+1) 表示你按错了一个灯,你就需要按回来,你还要按到 (i-1),还要加上你按错的这一次。

移项之后就可以得到:

[f_i=frac{n+(n-i) imes f_{i+1}}{i} ]

边界条件就是 (f_{n+1}=0),显然你不能拿 (f_{s+1}) 作为边界条件,因为你按错了就会变成 (s+1)

答案就是 ((sum_{i=k+1}^{s} f_i+k) imes n!)。当 (sle k) 的时候直接输出 (s) 即可。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 100005
#define mod 100003

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,k,cnt,a[MAXN],f[MAXN];

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}
void Add (int &x,int y){x = add (x,y);}

void makeit (int x){
	for (Int i = 1;i * i <= x;++ i) if (x % i == 0){
		a[i] ^= 1;
		if (i * i != x) a[x / i] ^= 1;
	}
}

signed main(){
	read (n,k);
	for (Int i = 1;i <= n;++ i) read (a[i]);
	for (Int i = n;i >= 1;-- i) if (a[i]) makeit (i),++ cnt;
	for (Int i = n;i >= k;-- i) f[i] = mul (add (n,mul (n - i,f[i + 1])),qkpow (i,mod - 2));
	int ans = 0;
	if (cnt > k){
		for (Int i = cnt;i > k;-- i) Add (ans,f[i]);
		Add (ans,k);
	}
	else ans = cnt;
	for (Int i = 1;i <= n;++ i) ans = mul (ans,i);
	write (ans),putchar ('
');
	return 0;
}
原文地址:https://www.cnblogs.com/Dark-Romance/p/14791754.html