大家都很强, 可与之共勉 。
题意:
B君在玩一个游戏,这个游戏由N个灯和N个开关组成,给定这N个灯的初始状态,下标为从1到N的正整数。每个灯有两个状态亮和灭,我们用1来表示这个灯是亮的,用0表示这个灯是灭的,游戏的目标是使所有灯都灭掉。但是当操作第i个开关时,所有编号为i的约数(包括1和i)的灯的状态都会被改变,即从亮变成灭,或者是从灭变成亮。
B君发现这个游戏很难,于是想到了这样的一个策略,每次等概率随机操作一个开关,直到所有灯都灭掉。这个策略需要的操作次数很多,B君想到这样的一个优化。如果当前局面,可以通过操作小于等于k个开关使所有灯都灭掉,那么他将不再随机,直接选择操作次数最小的操作方法(这个策略显然小于等于k步)操作这些开关。B君想知道按照这个策略(也就是先随机操作,最后小于等于k步,使用操作次数最小的操作方法)的操作次数的期望。这个期望可能很大,但是B君发现这个期望乘以N的阶乘一定是整数,所以他只需要知道这个整数对100003取模之后的结果。
输入输出格式
输入格式:
第一行两个整数N,k。
接下来一行N个整数,每个整数是0或者1,其中第i个整数表示第i个灯的初始情况。
1≤N≤100000,0≤k≤N
题解:
我萌先贪心好了,就不考虑随机,找最优解。
考虑到操作第
i
个开关的时候,只会影响到
然后我们来考虑如何处理期望的问题。
首先定义
f(x)
为
x
步后结束的期望,显然当
显然有这么个转移
f(x)=xn⋅f(x−1)+n−xn⋅f(x+1)+1
于是就得到了一个做法。
但是我当时脑抽想到了一个问题,
mmp
要是不能初始化
f(x)
怎么办,就是一个样例(
k<1
)……
于是就改了一种定义(其实它是可以做的见万古神犇WYS)
差分定义令
g(x)
为从
x
步第一次到
g(x)=xn⋅+n−xn⋅(g(x+1)+g(x)+1)
其中
x≤k||x=n
时,
g(x)=1
。
这样不用考虑初始化……
于是我们把最少步数找到,然后答案累加起来。
话说这道题完全如果给的模数不是质数,也可以做。
# include <bits/stdc++.h>
namespace In {
# define In_Len 2000000
static std :: streambuf *fb ( std :: cin.rdbuf ( ) ) ;
static char buf [In_Len], *ss ( 0 ), *tt ( 0 ) ;
# define pick( ) ( (ss == tt) ? ( tt = buf + fb -> sgetn ( ss = buf, In_Len ), ((ss == tt) ? -1 : *(ss ++)) ) :*(ss ++) )
inline char getc ( ) { register char c ; while ( isspace ( c = pick ( ) ) ) ; return c ; }
inline int read ( ) {
register int x, c ;
bool opt ( 1 ) ;
while ( ! isdigit ( c = pick ( ) ) && ( c ^ -1 ) && ( c ^ 45 ) ) ;
if ( c == 45 ) c = pick ( ), opt = 0 ;
for ( x = -48 + c ; isdigit ( c = pick ( ) ) ; ( x *= 10 ) += c - 48 ) ;
return opt ? x : -x ;
}
# undef pick
# undef In_Len
}
const int N = 100010 ;
bool a [N] ;
int pool [N * 18], *iter = pool, cnt [N], cur [N], *d [N] ;
int main ( ) {
int n, k, fac_n ( 1 ) ;
n = In :: read ( ), k = In :: read ( ) ;
for ( int i = 1 ; i <= n ; ++ i ) {
for ( int j = i ; j <= n ; j += i ) {
++ cnt [j] ;
}
}
for ( int i = 1 ; i <= n ; ++ i ) {
d [i] = iter ;
iter += cnt [i] ;
}
for ( int i = 1 ; i <= n ; ++ i )
for ( int j = i ; j <= n ; j += i ) {
d [j] [cur [j] ++] = i ;
}
for ( int i = 1 ; i <= n ; ++ i ) {
a [i] = ( bool ) ( In :: getc ( ) - 48 ) ;
fac_n = 1LL * fac_n * i % 100003 ;
}
int rt ( 0 ) ;
for ( int i = n ; i >= 1 ; -- i )
if ( a [i] ) {
for ( int j = cnt [i] - 1 ; j >= 0 ; -- j ) {
a [d [i] [j]] ^= 1 ;
}
++ rt ;
}
if ( rt <= k ) return printf ( "%d\n", 1LL * rt * fac_n % 100003 ), 0 ;
static int inv [N], f [N] ;
inv [1] = 1 ;
for ( int i = 2 ; i <= n ; ++ i ) inv [i] = 1LL * ( 100003 - 100003 / i ) * inv [100003 % i] % 100003 ;
for ( int i = 1 ; i <= k ; ++ i ) f [i] = 1 ;
f [n] = 1 ;
for ( int i = n - 1 ; i > k ; -- i ) f [i] = 1LL * ( 1LL * ( n - i ) * f [i + 1] % 100003 + n ) * inv [i] % 100003 ;
int ans ( 0 ) ;
for ( int i = 1 ; i <= rt ; ++ i ) ans += f [i] ;
printf ( "%d\n", 1LL * ans * fac_n % 100003 );
return 0 ;
}