Noip模擬49 2021.9.7
T1 reverse
又一道板子打假的掛分題,直接掛到倒二。。
考場上思路神奇,居然想到用$bfs$建邊然後跑最短路,
其實當時也想到了直接$bfs$,但是不知道為啥覺得$dij$屌就沒直接打$bfs$。。。
最可怕的是$dji$沒打對,以後可能要早操背板子了。。。
然後其實這題能卡過,因為$k$都特別小。
1 #include<bits/stdc++.h> 2 using namespace std; 3 namespace AE86{ 4 inline int read(){ 5 int x=0,f=1;char ch=getchar(); 6卡常暴力while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 8 }inline void write(int x,char opt='\n'){ 9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 12 }using namespace AE86; 13 14 inline int max(int a,int b){return a>b?a:b;} 15 inline int min(int a,int b){return a<b?a:b;} 16 17 int n,k,m,s,ans[100005],pos,wei,l,r; 18 bool vis[100005]; 19 double mid; 20 int q[100005],h=0,t=0; 21 namespace WSN{ 22 inline short main(){ 23 // freopen("reverse3.in","r",stdin); 24 // freopen("bl.out","w",stdout); 25 n=read(); k=read(); m=read(); s=read(); 26 for(register int i=1;i<=n;++i) ans[i]=-1; 27 for(register int i=1,jz;i<=m;++i) 28 jz=read(),vis[jz]=1,ans[jz]=-1; 29 q[++t]=s; ans[s]=0; vis[s]=1; 30 while(h<=t){ 31 pos=q[h++]; 32 l=max(1,pos-k+1); r=min(pos,n-k+1); 33 for(register int i=l;i<=r;++i){ 34 wei=i+(k-(pos-i+1)); 35 if(!vis[wei]){ 36 ans[wei]=ans[pos]+1; 37 vis[wei]=1; 38 q[++t]=wei; 39 } 40 } 41 } 42 for(register int i=1;i<=n;++i) 43 write(ans[i],' '); 44 return 0; 45 } 46 } 47 signed main(){return WSN::main();}
然後正解能優化到$O(n)$,就是使用一個連結串列,
發現每個$1$每次挪動的位置奇偶性都是一樣的,那麼初始化連結串列為$nxt_i=i+2$
然後$bfs$每次迴圈的時候直接找能跳到的位置並把連結串列指標指向迴圈最後一個元素。
1 #include<bits/stdc++.h> 2 using namespace std; 3 namespace AE86{ 4 inline int read(){ 5 int x=0,f=1;char ch=getchar(); 6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 8 }inline void write(int x,char opt='\n'){ 9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 12 }using namespace AE86; 13 14 inline int max(int a,int b){return a>b?a:b;} 15 inline int min(int a,int b){return a<b?a:b;} 16 17 int n,k,m,s,ans[100005],pos,l,r,nxt[100005],wei,nt; 18 bool vis[100005]; 19 int q[100005],h=0,t=0; 20 namespace WSN{ 21 inline short main(){ 22 n=read(); k=read(); m=read(); s=read(); 23 for(register int i=1;i<=n;++i) ans[i]=-1; 24 for(register int i=1;i<=m;++i) vis[read()]=1; 25 q[++t]=s; ans[s]=0; vis[s]=1; 26 for(int i=1;i<=n;i++) nxt[i]=i+2; 27 while(h<=t){ 28 pos=q[h++]; l=max(1,pos-k+1); r=min(pos,n-k+1); 29 wei=l*2+k-pos-1; 30 while(wei<=r*2+k-pos-1){ 31 nt=nxt[wei]; nxt[wei]=nxt[r*2+k-pos-1]; 32 if(!vis[wei]) ans[wei]=ans[pos]+1,vis[wei]=1,q[++t]=wei; 33 wei=nt; 34 } 35 } 36 for(register int i=1;i<=n;++i) write(ans[i],' '); 37 return 0; 38 } 39 } 40 signed main(){return WSN::main();}O(n)
T2 Silhouette
首先可以看出俯檢視是$min(a_i,b_j)$,就是說每個點疊最多隻有那麼多塊。
然後發現對於給出陣列排序前後計算的答案一樣,證明見 這裡
然後這樣我們對於每一段$S$相同的區域分別處理,這一塊區域之可能是矩形或者"L"形
為了不讓每一列相互影響,我們假設$f_i$表示至少有$i$行沒有一個塊的高度等於$S$,那麼對於$f_0$可以容斥出來
考慮$f_i$如何計算:
$f_i=C_{a}^{i}*(S^i*((S+1)^{a-i}-S^{a-i}))^b$
這個柿子是對於第一塊(也就是$S$是矩形)的情況。
(好吧這是粘別人的)
從$a$行裡面選擇$i$行不合法(就是沒有一個塊的高度等於$S$), $C_{a}^{i}$
然後對於每一列裡面有$i$行只能選擇$[0~S-1]$中的數,$S^i$
剩下的$a-i$行隨便選,然後減去那一行不是$S$的情況 $(S+1)^{a-i}-S^{a-i}$
共有$b$列並且互不影響。
然後看普遍情況
有以上三種,其中後兩種都可以按特殊情況告搞
考慮"L"形:分開搞
對於矩形的兩種情況,無非就是沒有了那一部分,可以認為舉行是一種特殊的L行。
為方便,我們不妨將L行區域按如下圖方式標號:
$f_i=C_a^i*(S^i*((S+1)^{a+c-i}-S^{a+c-i}))^b*(S^i*(S+1)^{a-i})^d$
因為上圖中紅色區域已經處理完畢,
所以對於藍色區域,其已經滿足行,而沒有滿足列,
對於綠色區域,其已經滿足列,沒有滿足行
關於組合數,因為前面的$c$已經處理過,是合法的,所以我們只考慮在$a$行中選擇不和法行,處理$1$區域與特殊部分同理。
然後處理綠色的$2$部分,這一部分列已經滿足,所以關於特殊部分裡面的減去一個$S^{a-i}$來保證合法就沒有必要了
於是就直接$*(S^i*(S+1)^{a-i})^d$就可以了
這些東西都懂了程式碼就沒什麼了,很好理解。
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=1e5+5,mod=1e9+7; 16 int n,a[NN],b[NN],m[NN<<1],has,ans=1; 17 int h[NN],v[NN]; 18 inline int qmo(int a,int b){int ans=1,c=mod;a%=c;while(b){if(b&1)ans=ans*a%c;b>>=1;a=a*a%c;}return ans;} 19 inline void pre(){ 20 h[0]=h[1]=1; v[0]=v[1]=1; 21 for(int i=2;i<=100000;i++) h[i]=h[i-1]*i%mod; 22 v[100000]=qmo(h[100000],mod-2); 23 for(int i=99999;i>=2;i--) v[i]=v[i+1]*(i+1)%mod; 24 } 25 inline int C(int n,int m){ 26 if(n<m||n<0||m<0) return 0; 27 return h[n]*v[n-m]%mod*v[m]%mod; 28 } 29 30 inline int calc(int a,int b,int c,int d,int s,int ans=0){ 31 for(int i=0;i<=a;i++){ 32 int res=C(a,i)*qmo(qmo(s,i)*((qmo(s+1,a+c-i)-qmo(s,a+c-i)+mod)%mod)%mod,b)%mod*qmo(qmo(s,i)*qmo(s+1,a-i)%mod,d)%mod; 33 if(i&1) ans=(ans-res+mod)%mod;else ans=(ans+res)%mod; 34 } return ans; 35 } 36 37 namespace WSN{ 38 inline short main(){ 39 n=read(); pre(); 40 for(int i=1;i<=n;i++) a[i]=read(),m[i]=a[i]; 41 for(int i=1;i<=n;i++) b[i]=read(),m[i+n]=b[i]; 42 sort(a+1,a+n+1); sort(b+1,b+n+1); 43 if(a[n]!=b[n]) return puts("0"),0; 44 sort(m+1,m+2*n+1); has=unique(m+1,m+2*n+1)-m-1; 45 int pa=n+1,pb=n+1,na=n,nb=n; 46 for(int i=has;i;i--){ 47 while(a[na-1]==m[i]&&na-1) --na; 48 while(b[nb-1]==m[i]&&nb-1) --nb; 49 ans=ans*calc(pa-na,pb-nb,n-pa+1,n-pb+1,m[i])%mod; 50 pa=na; pb=nb; 51 } write(ans); 52 return 0; 53 } 54 } 55 signed main(){return WSN::main();}View Code
T3 seat
據說$dp$很玄學,不大會。。。。
只知道$skyh$大神傾情壓行程式碼加註釋。