1. 程式人生 > 其它 >luogu P3750 [六省聯考 2017] 分手是祝願

luogu P3750 [六省聯考 2017] 分手是祝願

題面傳送門
因為有50pts都是\(k=n\)所以先考慮這個。
考慮從後往前掃,如果掃到當前點發現當前點是亮的,那麼當前點一定會操作一次,因為前面的點操作不到當前這個點。這樣可以做出最小的步數。
然後交上去就有80pts了(
觀察這個東西不難發現一個性質:如果\(i\)在最優方案中沒有被按到但是我按了,那麼最後的最優步數一定會+1
所以只要求出\(f_i\)表示現在有\(i\)個點的期望步數,設當前狀態的最優步數為\(k\),則初始\(f_{k}=0\),有轉移方程\(f_{i}=1+\frac{i}{n}f_{i-1}+\frac{n-i}{n}f_{i+1}\)
發現轉移成環好像不太妙,直接暴力高斯消元好像能多5到10分,不過因為是一條鏈所以直接指定一個端點為主元然後在另一個端點解出來即可。
時間複雜度看你怎麼列舉約數,蒟蒻寫了個\(O(n\sqrt n)\)

的。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (1<<20)
#define mod 100003
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,k,cnt,A[N+5],Id;ll Inv[N+5],F1[N+5],F2[N+5],Ans;
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;} 
int main(){
	freopen("1.in","r",stdin);
	RI i,j;scanf("%d%d",&n,&k);for(i=1;i<=n;i++) scanf("%d",&A[i]);
	for(i=n;i;i--){if(!A[i])continue;for(j=1;j*j<=i;j++) i%j==0&&(A[j]^=1,j*j!=i&&(A[i/j]^=1));cnt++;}
	if(cnt<=k){for(i=1;i<=n;i++) cnt=1ll*cnt*i%mod;printf("%d\n",cnt);return 0;}for(i=1;i<=n;i++)Inv[i]=mpow(i);F2[k]=k;F1[k+1]=1;
	for(i=k+1;i<n;i++) F1[i+1]=n*Inv[n-i]%mod*(F1[i]-F1[i-1]*i%mod*Inv[n]%mod)%mod,F2[i+1]=n*Inv[n-i]%mod*(F2[i]-1-F2[i-1]*i%mod*Inv[n]%mod)%mod;
	Ans=(F2[n-1]-F2[n]+1)*mpow(F1[n]-F1[n-1])%mod;Ans=((Ans*F1[cnt]+F2[cnt])%mod+mod)%mod;for(i=1;i<=n;i++) Ans=Ans*i%mod;printf("%lld\n",Ans);
}