<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【比賽記錄】2025 暑假集訓模擬賽合集Ⅱ

      2025CSP-S模擬賽35

      A B C D Sum Rank
      100 40 40 - 180 3/19

      A. 114514

      分別考慮 \(b\) 的每一位可以填什么。因為 \(a\) 是字典序最小的,所以對于每一位 \(a\) 不能有更小的選擇,于是 \(b_i\le a_i\) 且要求 \([b_i,a_i]\)\(a_i\) 及之前都出現過。用鏈表可以做到線性復雜度。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=4e6+5,mod=1e9+7;
      int n,a[maxn],pre[maxn],nxt[maxn];
      int main(){
      	freopen("trans.in","r",stdin);
      	freopen("trans.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      	}
      	for(int i=0;i<=4e6;i++){
      		nxt[i]=i+1,pre[i+1]=i;
      	}
      	int ans=1;
      	for(int i=1;i<=n;i++){
      		ans=ans*1ll*(a[i]-pre[a[i]])%mod;
      		nxt[pre[a[i]]]=nxt[a[i]];
      		pre[nxt[a[i]]]=pre[a[i]];
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 沉默樂團

      容易發現,我們只需判斷不交的前后綴即可。考慮前綴和后綴都是嚴格單增的,于是考慮將它們歸并起來,考察臨項是否相等。考慮 DP,設 \(f_{i,j,k}\) 表示考慮到了 \(i\) 的前綴,\(j\) 的后綴,后綴 \(-\) 前綴 \(=k\) 的方案數,于是有轉移:

      \[f_{i,j,k}\to f_{i+1,j,k-x}\quad x\in[l_{i+1},r_{i+1}]\land k>0\\ f_{i,j,k}\to f_{i,j-1,k+x}\quad x\in[l_{j-1},r_{j-1}]\land k\le0 \]

      注意 \(k\ne0\),初始值 \(f_{0,n+1,0}=1\)。答案即為 \(\sum_{i=0}^{n}f_{i,i+1,k}\)。差分優化,時間復雜度 \(O(n^2m)\)

      Code
      #include<bits/stdc++.h>
      #define il inline
      using namespace std;
      namespace asbt{
      const int V=2e3+5,mod=1e9+7;
      il int pls(int x,int y){
      	return x+y<mod?x+y:x+y-mod;
      }
      il int sub(int x,int y){
      	return x<y?x-y+mod:x-y;
      }
      il void add(int &x,int y){
      	x=pls(x,y);
      }
      il void mns(int &x,int y){
      	x=sub(x,y);
      }
      int n,ll[55],rr[55],f[55][55][V<<1];
      il void upd(int *f,int l,int r,int v){
      	add(f[l+V],v),mns(f[r+V+1],v);
      }
      int main(){
      	freopen("orchestra.in","r",stdin);
      	freopen("orchestra.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		cin>>ll[i]>>rr[i];
      	}
      	upd(f[0][n+1],0,0,1);
      	for(int len=n+2;len>=2;len--){
      		for(int i=0,j=len-1;j<=n+1;i++,j++){
      			for(int k=-2000;k<=2000;k++){
      				add(f[i][j][k+V],f[i][j][k+V-1]);
      				if(k>0){
      					int l=k-rr[i+1],r=k-ll[i+1];
      					if(l>0||r<0){
      						upd(f[i+1][j],l,r,f[i][j][k+V]);
      					}
      					else{
      						upd(f[i+1][j],l,-1,f[i][j][k+V]);
      						upd(f[i+1][j],1,r,f[i][j][k+V]);
      					}
      				}
      				else{
      					int l=k+ll[j-1],r=k+rr[j-1];
      					if(l>0||r<0){
      						upd(f[i][j-1],l,r,f[i][j][k+V]);
      					}
      					else{
      						upd(f[i][j-1],l,-1,f[i][j][k+V]);
      						upd(f[i][j-1],1,r,f[i][j][k+V]);
      					}
      				}
      			}
      		}
      	}
      	int ans=0;
      	for(int i=0;i<=n;i++){
      		for(int j=-2000;j<=2000;j++){
      			add(ans,f[i][i+1][j+V]);
      		}
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. 深黯「軍團」

      考慮將逆序對拆成每一位的貢獻,即每一位計算它后面有多少 \(<a_i\)。打個表出來長這樣:

      打表
      1 2 3 4 |0 0 0 0
      1 2 4 3 |0 0 1 0
      1 3 2 4 |0 1 0 0
      1 3 4 2 |0 1 1 0
      1 4 2 3 |0 2 0 0
      1 4 3 2 |0 2 1 0
      2 1 3 4 |1 0 0 0
      2 1 4 3 |1 0 1 0
      2 3 1 4 |1 1 0 0
      2 3 4 1 |1 1 1 0
      2 4 1 3 |1 2 0 0
      2 4 3 1 |1 2 1 0
      3 1 2 4 |2 0 0 0
      3 1 4 2 |2 0 1 0
      3 2 1 4 |2 1 0 0
      3 2 4 1 |2 1 1 0
      3 4 1 2 |2 2 0 0
      3 4 2 1 |2 2 1 0
      4 1 2 3 |3 0 0 0
      4 1 3 2 |3 0 1 0
      4 2 1 3 |3 1 0 0
      4 2 3 1 |3 1 1 0
      4 3 1 2 |3 2 0 0
      4 3 2 1 |3 2 1 0
      

      發現每一列都在以 \((n-i+1)!\) 為循環周期循環,且第 \(i+1\) 列經過一個循環周期后第 \(i\) 列答案加一。具體的證明:后 \(n-i\) 位全排列一次過程中 \(i\) 的答案不會變,而將 \(i\) 和后面某個位置交換一定會使逆序對加一。

      于是我們考慮對于每一列單獨計算。以下將相同的數組成的段叫一塊。首先是一個散塊,我們可以通過第 \(i+1\) 列第一個循環節的開頭位置算出它的長度。然后是幾個整塊,它們和前面那個散塊組成一個散循環節,這些整塊直接暴力枚舉算出。然后是幾個整循環節,直接等差數列求和即可 \(O(1)\) 算出。后面又是一個散循環節,暴力算即可。

      考慮時間復雜度,\(20!>10^{18}\),于是 \(n-i\ge19\) 后沒有整循環節,\(n-i\ge20\) 后沒有整塊。所以時間復雜度就是 \(O(n\log n)\)

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=5e5+5,inf=2e18;
      int n,m,mod,a[maxn],fac[maxn];
      struct{
      	#define lowbit(x) (x&-x)
      	int tr[maxn];
      	il void add(int p,int v){
      		for(;p<=n;p+=lowbit(p)){
      			tr[p]+=v;
      		}
      	}
      	il int query(int p){
      		int res=0;
      		for(;p;p-=lowbit(p)){
      			res+=tr[p];
      		}
      		return res;
      	}
      	#undef lowbit
      }F;
      int main(){
      	freopen("army.in","r",stdin);
      	freopen("army.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>mod;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      	}
      	fac[0]=1;
      	for(int i=1;i<=19;i++){
      		fac[i]=fac[i-1]*i;
      //		cout<<fac[i]<<" ";
      	}
      //	cout<<"\n";
      	for(int i=20;i<=n;i++){
      		fac[i]=inf;
      	}
      	int ans=0;
      	for(int i=n,lst0=1,chu,len;i;i--){
      //		cout<<lst0<<"\n";
      		chu=F.query(a[i]);
      		if(lst0>m){
      			(ans+=m%mod*chu)%=mod;
      			goto togo;
      		}
      		(ans+=(lst0-1)%mod*chu)%=mod;
      		if(lst0>1){
      			chu++;
      		}
      		for(;chu<=n-i;chu++){
      			if(lst0+fac[n-i]-1>m){
      				(ans+=(m-lst0+1)%mod*chu)%=mod;
      				lst0=inf;
      				goto togo;
      			}
      			(ans+=fac[n-i]%mod*chu)%=mod;
      			lst0+=fac[n-i];
      		}
      		(ans+=(m-lst0+1)/fac[n-i+1]%mod*(fac[n-i]%mod)%mod*((n-i+1)*(n-i)/2%mod))%=mod;
      		len=(m-lst0+1)%fac[n-i+1];
      		for(int j=0;;j++){
      			if(len<fac[n-i]){
      				(ans+=len%mod*j)%=mod;
      				break;
      			}
      			(ans+=fac[n-i]%mod*j)%=mod;
      			len-=fac[n-i];
      		}
      		togo:;
      		F.add(a[i],1);
      //		cout<<ans<<"\n";
      	}
      	cout<<ans;
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      /*
      10 6 998244353
      10 6 2 9 8 3 7 1 5 4 
      */
      

      D. 終末螺旋

      2025CSP-S模擬賽36

      A B C D Sum Rank
      40 10 20 12 82 21/23

      A. 購買飲料

      首先判斷 \(-1\) 情況:如果能買得起 \(a\) 瓶,并且 \(b\) 塊錢也能買得起 \(a\) 瓶,那么輸出 \(-1\)。然后我們就不斷地買 \(a\) 瓶并換錢直到買不起 \(a\) 瓶即可。時間復雜度 \(O(T)\)

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      using namespace std;
      namespace asbt{
      int T,n,m,a,b;
      int main(){
      	freopen("buy.in","r",stdin);
      	freopen("buy.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--){
      		cin>>n>>m>>a>>b;
      		if(n<a*m){
      			cout<<n/m<<'\n';
      		}
      		else if(b>=a*m){
      			cout<<-1<<'\n';
      		}
      		else{
      			int t=(n-a*m)/(a*m-b)+1,ans=t*a;
      			n-=t*(a*m-b),ans+=n/m;
      			cout<<ans<<'\n';
      		}
      	}
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      B. 多邊形

      首先判斷是否有一種顏色只有一個點,如果有,那么將這個點和其他所有點相連即可。否則,一定有相鄰的三個顏色不同的點,將它們分成一個小三角形,遞歸下去即可。可以發現按照這樣的構造一定有解。需要鏈表和棧。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=1e6+5;
      int n,pre[maxn],nxt[maxn],_1=1,c1,c2,c3;
      bool ban[maxn];
      string s;
      stack<int> stk,R,G,B;
      il bool chk(int x){
      	char hp[3]={s[pre[x]],s[x],s[nxt[x]]};
      	sort(hp,hp+3);
      	return hp[0]=='B'&&hp[1]=='G'&&hp[2]=='R';
      }
      int main(){
      //	freopen("B4.in","r",stdin);
      	freopen("polygon.in","r",stdin);
      	freopen("polygon.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>s;
      	s=" "+s;
      	for(int i=1;i<=n;i++){
      		pre[i]=i==1?n:i-1;
      		nxt[i]=i==n?1:i+1;
      		if(chk(i)){
      			stk.push(i);
      //			cout<<i<<'\n';
      		}
      		switch(s[i]){
      		case 'R':{
      			R.push(i),c1++;
      			break;
      		}
      		case 'G':{
      			G.push(i),c2++;
      			break;
      		}
      		default:{
      			B.push(i),c3++;
      			break;
      		}
      	}
      	}
      	while(n>3){
      		if(c1==1){
      			while(ban[R.top()]){
      				R.pop();
      			}
      			_1=R.top();
      		}
      		else if(c2==1){
      			while(ban[G.top()]){
      				G.pop();
      			}
      			_1=G.top();
      		}
      		else if(c3==1){
      			while(ban[B.top()]){
      				B.pop();
      			}
      			_1=B.top();
      		}
      		else{
      			goto togo;
      		}
      		for(int i=nxt[nxt[_1]];;i=nxt[i]){
      			cout<<i<<' '<<_1<<'\n';
      			if(i==pre[pre[_1]]){
      				break;
      			}
      		}
      		break;
      		togo:;
      		while(stk.size()){
      			int x=stk.top();
      			stk.pop();
      			if(ban[x]||!chk(x)){
      				continue;
      			}
      			cout<<pre[x]<<' '<<nxt[x]<<'\n';
      			n--,ban[x]=1;
      			switch(s[x]){
      				case 'R':{
      					c1--;
      					break;
      				}
      				case 'G':{
      					c2--;
      					break;
      				}
      				default:{
      					c3--;
      					break;
      				}
      			}
      			if(x==_1){
      				_1=nxt[x];
      			}
      //			cout<<"a "<<s[x]<<' '<<s[pre[x]]<<' '<<s[nxt[x]]<<'\n';
      			nxt[pre[x]]=nxt[x];
      			pre[nxt[x]]=pre[x];
      			if(chk(pre[x])){
      				stk.push(pre[x]);
      			}
      			if(chk(nxt[x])){
      				stk.push(nxt[x]);
      			}
      			break;
      		}
      //		cout<<'\n';
      //		cout<<n<<' '<<c1<<' '<<c2<<' '<<c3<<'\n';
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. 二分圖最大權匹配

      ,神秘網絡流。

      D. 飛毯

      ,神秘構造。

      2025CSP-S模擬賽37

      A B C D Sum Rank
      100 - 25 - 125 19/25

      A. 新的階乘

      我們需要一個線性做法,因此暴力枚舉每個數的每一個質因子是無法接受的,考慮用歐拉篩找出每個數的最小質因子 \(\operatorname{mpf}(x)\),將 \(x\) 的冪次下放給 \(\operatorname{mpf}(x)\)\(\frac{x}{\operatorname{mpf}(x)}\) 即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=1e7+5;
      int n,prn,prm[maxn],mpf[maxn];
      ll fac[maxn];
      bool npr[maxn];
      il void euler(int n=1e7){
      	for(int i=2;i<=n;i++){
      		if(!npr[i]){
      			prm[++prn]=i;
      			mpf[i]=i;
      		}
      		for(int j=1;j<=prn&&i*1ll*prm[j]<=n;j++){
      			npr[i*prm[j]]=1;
      			mpf[i*prm[j]]=prm[j];
      			if(i%prm[j]==0){
      				break;
      			}
      		}
      	}
      }
      int main(){
      //	freopen("my.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	euler();
      	cin>>n;
      	for(int i=2;i<=n;i++){
      		fac[i]=n-i+1;
      	}
      	for(int i=n;i>1;i--){
      //		cout<<mpf[i]<<" ";
      		if(npr[i]){
      			fac[mpf[i]]+=fac[i];
      			fac[i/mpf[i]]+=fac[i];
      		}
      	}
      	bool flag=0;
      	for(int i=1;i<=prn;i++){
      		if(fac[prm[i]]){
      			if(!flag){
      				cout<<"f("<<n<<")=";
      				flag=1;
      			}
      			else{
      				cout<<'*';
      			}
      			cout<<prm[i];
      			if(fac[prm[i]]>1){
      				cout<<'^'<<fac[prm[i]];
      			}
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 博弈樹

      首先可以發現如果先手在直徑端點上那么必勝。接下來雙方一定不能走到直徑端點上,否則對方再走到另一個端點就輸了。因此我們可以直接將所有直徑端點刪掉。那么在刪后的這棵樹上,雙方一定還是不能走到直徑端點上,否則另一方走到另一個端點上后自己將不得不走到原樹直徑端點上。那么一層層刪點,如果最后剩下一個點了那么先手必敗,否則必勝。考慮這個條件等價于什么,發現就是如果起始點在直徑中點那么先手必敗,否則先手必勝,dfs 預處理即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      const int maxn=1e5+5;
      int n,m,d1,d2,ans,dep[maxn],mxd[maxn],des[maxn];
      vector<int> e[maxn];
      il void dfs1(int u,int fa){
      	mxd[u]=dep[u]=dep[fa]+1,des[u]=u;
      	for(int v:e[u]){
      		if(v==fa){
      			continue;
      		}
      		dfs1(v,u);
      		if(mxd[v]>mxd[u]){
      			mxd[u]=mxd[v],des[u]=des[v];
      		}
      	}
      }
      il void dfs2(int u,int fa){
      	des[dep[u]]=u;
      	if(u==d2){
      		ans=des[(dep[u]+1)>>1];
      	}
      	for(int v:e[u]){
      		if(v==fa){
      			continue;
      		}
      		dfs2(v,u);
      	}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1,u,v;i<n;i++){
      		cin>>u>>v;
      		e[u].pb(v),e[v].pb(u);
      	}
      	dfs1(1,0),d1=des[1];
      	dfs1(d1,0),d2=des[d1];
      	if(dep[d2]&1){
      		dfs2(d1,0);
      	}
      	while(m--){
      		int u;
      		cin>>u;
      		cout<<(u==ans?"Bob":"Alice")<<'\n';
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. 劃分

      發現我們的劃分一定是一段長為 \(n-k+1\) 的和 \(k-1\) 段長為 \(1\) 的。考慮每個數對應的位權,那么我們一定是要找到最大的一段 \(n-k+1\),哈希加二分求出 LCP 即可比較大小。考慮方案數,發現因為 \(1\) 的數量是固定的,所以最后一位是 \(0\) 還是 \(1\) 都是無所謂的,所以找到有多少個長為 \(n-k+1\) 的段與最優段的前 \(n-k\) 位相同即可。注意 \(n=k\) 時方案數為 \(1\)。但是還有一個問題,如果這個最優段有前導零,那么方案數是會變多的,換句話說如果前 \(k-1\) 位都是 \(0\) 那么一定是在前導零中隨便分 \(\ge k-1\) 次,組合數計算即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define ull unsigned ll
      using namespace std;
      namespace asbt{
      const int maxn=2e6+5,mod=998244353;
      const ull bas1=131;
      const ll bas2=233,mod2=1e9+7;
      int n,m,fac[maxn],inv[maxn];
      ull ha1[maxn],pw1[maxn];
      ll ha2[maxn],pw2[maxn];
      string s;
      il int qpow(int x,int y=mod-2){
      	int res=1;
      	while(y){
      		if(y&1){
      			res=res*1ll*x%mod;
      		}
      		x=x*1ll*x%mod,y>>=1;
      	}
      	return res;
      }
      il int C(int x,int y){
      	if(x<y||y<0){
      		return 0;
      	}
      	return fac[x]*1ll*inv[y]%mod*inv[x-y]%mod;
      }
      il void chk(){
      	if(n==m){
      		int ans=0;
      		for(int i=1;i<=n;i++){
      			ans+=s[i]^48;
      		}
      		cout<<ans<<' '<<1;
      		exit(0);
      	}
      	for(int i=1;i<m;i++){
      		if(s[i]=='1'){
      			return ;
      		}
      	}
      	int ans=0,pos=n;
      	for(int i=1;i<=n;i++){
      		ans=(ans*2+(s[i]^48))%mod;
      		if(pos==n&&s[i]=='1'){
      			pos=i;
      		}
      	}
      	fac[0]=1;
      	for(int i=1;i<=n;i++){
      		fac[i]=fac[i-1]*1ll*i%mod;
      	}
      	inv[n]=qpow(fac[n]);
      	for(int i=n;i;i--){
      		inv[i-1]=inv[i]*1ll*i%mod;
      	}
      	int res=0;
      	for(int i=m-1;i<pos;i++){
      		(res+=C(pos-1,i))%=mod;
      	}
      	cout<<ans<<' '<<res;
      	exit(0);
      }
      il ull Ha1(int l,int r){
      	return ha1[r]-ha1[l-1]*pw1[r-l+1];
      }
      il ll Ha2(int l,int r){
      	return (ha2[r]-ha2[l-1]*pw2[r-l+1]%mod2+mod2)%mod2;
      }
      il bool Eq(int l1,int r1,int l2,int r2){
      	return Ha1(l1,r1)==Ha1(l2,r2)&&Ha2(l1,r1)==Ha2(l2,r2);
      }
      il int lcp(int p,int q){
      	int l=0,r=n-m+1;
      	while(l<r){
      		int mid=(l+r+1)>>1;
      		if(Eq(p,p+mid-1,q,q+mid-1)){
      			l=mid;
      		}
      		else{
      			r=mid-1;
      		}
      	}
      	return l;
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>s;
      	s=" "+s;
      	chk();
      	pw1[0]=pw2[0]=1;
      	for(int i=1;i<=n;i++){
      		pw1[i]=pw1[i-1]*bas1;
      		pw2[i]=pw2[i-1]*bas2%mod2;
      		ha1[i]=ha1[i-1]*bas1+s[i];
      		ha2[i]=(ha2[i-1]*bas2+s[i])%mod2;
      	}
      	int p=1;
      	for(int i=2;i<=m;i++){
      		int t=lcp(p,i);
      		if(t<n-m+1&&s[p+t]<s[i+t]){
      			p=i;
      		}
      	}
      	int ans=0,cnt=0;
      	for(int i=p,j=1;j<=n-m+1;i++,j++){
      		ans=(ans*2+(s[i]^48))%mod;
      	}
      	for(int i=1;i<p;i++){
      		ans+=s[i]^48;
      	}
      	for(int i=p+n-m+1;i<=n;i++){
      		ans+=s[i]^48;
      	}
      	ans%=mod;
      	for(int i=1;i<=m;i++){
      		if(Eq(i,i+n-m-1,p,p+n-m-1)){
      			cnt++;
      		}
      	}
      	cout<<ans<<' '<<cnt;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      D. 燈籠

      考慮 DP。設 \(f_{l,r}\) 表示可以到達的高度區間為 \([l,r]\) 的最小花費,每次枚舉出發點 \(i\) 進行一次 DP,時間復雜度 \(O(nk^3)\)

      考慮去掉枚舉 \(i\) 的操作,考慮轉換定義與轉移順序(轉置)。設 \(f_{i,l,r}\) 表示當前在 \(i\),高度區間為 \([l,r]\),將 \([1,n]\) 走遍的最小花費,考慮優化狀態,容易發現 \([l,r]\) 其實是 \([a_u,b_v]\),這樣就可以不用記錄 \(i\),于是設 \(f_{u,v}\) 表示合法海拔區間為 \([a_u,b_v]\),且區間經過了 \(u\)\(v\),將 \([1,n]\) 走遍的最小花費,于是有轉移:

      • \(f_{u,v}\leftarrow f_{u,p}+c_p\)
      • \(f_{u,v}\leftarrow f_{p,v}+c_p\)
      • \(f_{u,v}\leftarrow f_{p,p}+c_p\)

      此時的時間復雜度為 \(O(nk^2)\),考慮優化轉移。我們顯然要按照 \(a\) 升序的順序枚舉 \(u\)\(b\) 降序的順序枚舉 \(v\),那么對于 \(v'<v\),如果 \(f_{u,p}\) 不能向 \(f_{u,v}\) 轉移,那么一定不能向 \(f_{u,v'}\) 轉移。于是用小根堆對每個 \(u\) 維護合法的 \(f_{u,p}+c_p\) 即可。對于第三個轉移,將其分步成 \(f_{p,p}\to f_{u,p}/f_{p,v}\to f_{u,v}\),特判即可。時間復雜度 \(O(k^2\log k)\)

      Code
      #include<bits/stdc++.h>
      #define il inline
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      const int maxn=2e3+5,inf=0x7f7f7f7f;
      int n,m,h[maxn],p[maxn],c[maxn],a[maxn],b[maxn];
      int I[maxn],J[maxn],ll[maxn][2],rr[maxn][2],f[maxn][maxn];
      priority_queue<pii> q1[maxn],q2[maxn];
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>h[i];
      	}
      	for(int i=1;i<=m;i++){
      		cin>>p[i]>>c[i]>>a[i]>>b[i];
      		I[i]=J[i]=i;
      	}
      	sort(I+1,I+m+1,[](int x,int y){return a[x]<a[y];});
      	sort(J+1,J+m+1,[](int x,int y){return b[x]>b[y];});
      	for(int i=1;i<=m;i++){
      		ll[i][0]=ll[i][1]=rr[i][0]=rr[i][1]=p[i];
      		while(ll[i][0]>1&&h[ll[i][0]-1]>=a[i]){
      			ll[i][0]--;
      		}
      		while(rr[i][0]<n&&h[rr[i][0]+1]>=a[i]){
      			rr[i][0]++;
      		}
      		while(ll[i][1]>1&&h[ll[i][1]-1]<=b[i]){
      			ll[i][1]--;
      		}
      		while(rr[i][1]<n&&h[rr[i][1]+1]<=b[i]){
      			rr[i][1]++;
      		}
      	}
      	memset(f,0x7f,sizeof(f));
      	for(int i=1;i<=m;i++){
      		for(int j=1;j<=m;j++){
      			int x=I[i],y=J[j];
      			if(p[x]<ll[y][1]||p[x]>rr[y][1]||p[y]<ll[x][0]||p[y]>rr[x][0]){
      				continue;
      			}
      			if(a[y]<a[x]&&b[x]>b[y]){
      				continue;
      			}
      			int l=max(ll[x][0],ll[y][1]),r=min(rr[x][0],rr[y][1]);
      			if(l==1&&r==n){
      				f[x][y]=0;
      			}
      			else if(a[y]<a[x]){
      				f[x][y]=f[y][y];
      			}
      			else if(b[x]>b[y]){
      				f[x][y]=f[x][x];
      			}
      			else{
      				while(q1[x].size()){
      					int t=q1[x].top().sec;
      					if(p[t]<l||p[t]>r||b[t]<a[x]||a[t]>b[y]){
      						q1[x].pop();
      					}
      					else{
      						break;
      					}
      				}
      				if(q1[x].size()){
      					f[x][y]=min(f[x][y],-q1[x].top().fir);
      				}
      				while(q2[y].size()){
      					int t=q2[y].top().sec;
      					if(p[t]<l||p[t]>r||b[t]<a[x]||a[t]>b[y]){
      						q2[y].pop();
      					}
      					else{
      						break;
      					}
      				}
      				if(q2[y].size()){
      					f[x][y]=min(f[x][y],-q2[y].top().fir);
      				}
      			}
      			if(f[x][y]<inf){
      				q1[x].push(mp(-f[x][y]-c[y],y));
      				q2[y].push(mp(-f[x][y]-c[x],x));
      			}
      		}
      	}
      	for(int i=1;i<=m;i++){
      		if(h[p[i]]<a[i]||h[p[i]]>b[i]||f[i][i]>=inf){
      			cout<<-1<<'\n';
      		}
      		else{
      			cout<<f[i][i]+c[i]<<'\n';
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      2025CSP-S模擬賽38

      A B C D Sum Rank
      80 20 10 - 110 9/21

      A. 黑暗料理

      原(bushi

      首先可以發現所有的 \(1\) 只能留一個。然后我們考慮將和為質數的 \(x\)\(y\) 連邊,此時 \(x+y\) 一定為奇數,也就是 \(x\)\(y\) 奇偶性不同,于是沒有奇環。此時我們要求最大獨立集,跑匈牙利即可。需要 Miller-Rabin。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      const int prm[]={2,3,5,7,11};
      int T,n,m,a[755],mch[755];
      bool vis[755];
      vector<int> e[755];
      il int qpow(int x,int y,int p){
      	int res=1;
      	while(y){
      		if(y&1){
      			res=res*1ll*x%p;
      		}
      		x=x*1ll*x%p,y>>=1;
      	}
      	return res;
      }
      il bool mlrb(int x){
      	if(x<=11){
      		for(int i:prm){
      			if(x==i){
      				return 1;
      			}
      		}
      		return 0;
      	}
      	int t=x-1,k=0;
      	while(t%2==0){
      		t>>=1,k++;
      	}
      	for(int i:prm){
      		int a=qpow(i,t,x);
      		for(int j=1;j<=k;j++){
      			int b=a*1ll*a%x;
      			if(b==1&&a!=1&&a!=x-1){
      				return 0;
      			}
      			a=b;
      		}
      		if(a!=1){
      			return 0;
      		}
      	}
      	return 1;
      }
      il bool dfs(int u){
      	for(int v:e[u]){
      		if(vis[v]){
      			continue;
      		}
      		vis[v]=1;
      		if(mch[v]==-1||dfs(mch[v])){
      			mch[v]=u;
      			return 1;
      		}
      	}
      	return 0;
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--){
      		cin>>n,m=0;
      		bool flag=0;
      		for(int i=1,x;i<=n;i++){
      			cin>>x;
      			if(x>1){
      				a[++m]=x;
      			}
      			else if(!flag){
      				flag=1,a[++m]=x;
      			}
      		}
      		for(int i=1;i<=m;i++){
      			for(int j=i+1;j<=m;j++){
      				if(mlrb(a[i]+a[j])){
      					e[i].pb(j),e[j].pb(i);
      //					cout<<i<<' '<<j<<'\n';
      				}
      			}
      		}
      		int ans=0;
      		for(int i=1;i<=m;i++){
      			mch[i]=-1;
      		}
      		for(int i=1;i<=m;i++){
      			for(int j=1;j<=m;j++){
      				vis[j]=0;
      			}
      			ans+=dfs(i);
      		}
      		cout<<m-ans/2<<'\n';
      		for(int i=1;i<=m;i++){
      			e[i].clear();
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 爆炸

      如果一個炸彈是被橫著引爆的,那么貪心地想,它一定要豎著炸。于是對每一行和每一列設點,對于一個炸彈 \((x,y)\),將第 \(x\) 行和第 \(y\) 列連邊,于是獲得了若干連通塊。考慮如果連通塊內有環,那么隨便引爆環上一個點,一定是能把這個連通塊炸完的,直接計算答案即可。如果沒有環,那么這一定是一棵樹,我們要選擇一條邊,只保留它的一邊,另一邊舍去。顯然舍去一個葉子節點是最優的,暴力枚舉葉子即可。時間復雜度 \(O(nm)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      const int maxn=6e3+5;
      int n,m,a,b,cnt,lfn,ans,fa[maxn],f[maxn][maxn],hp[maxn],lf[maxn];
      bool tag[maxn],vis[maxn];
      string s[maxn];
      vector<int> e[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void dfs1(int u){
      	if(vis[u]){
      		return;
      	}
      	hp[++cnt]=u;
      	vis[u]=1;
      	if(u<=n){
      		for(int i=1;i<=m;i++){
      			if(s[u][i]=='k'&&++f[u][i]==1){
      				ans++;
      			}
      		}
      	}
      	else{
      		for(int i=1;i<=n;i++){
      			if(s[i][u-n]=='k'&&++f[i][u-n]==1){
      				ans++;
      			}
      		}
      	}
      	for(int v:e[u]){
      		dfs1(v);
      	}
      }
      il void dfs2(int u,int fa){
      	hp[++cnt]=u;
      	if(e[u].size()==1){
      		lf[++lfn]=u;
      	}
      	if(u<=n){
      		for(int i=1;i<=m;i++){
      			if(s[u][i]=='k'&&++f[u][i]==1){
      				ans++;
      			}
      		}
      	}
      	else{
      		for(int i=1;i<=n;i++){
      			if(s[i][u-n]=='k'&&++f[i][u-n]==1){
      				ans++;
      			}
      		}
      	}
      	for(int v:e[u]){
      		if(v==fa){
      			continue;
      		}
      		dfs2(v,u);
      	}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>a>>b;
      	for(int i=1;i<=n+m;i++){
      		fa[i]=i;
      	}
      	for(int i=1;i<=n;i++){
      		cin>>s[i];
      		s[i]=" "+s[i];
      		for(int j=1;j<=m;j++){
      			if(s[i][j]=='b'){
      //				cout<<i<<' '<<n+j<<'\n';
      				e[i].pb(n+j),e[n+j].pb(i);
      				int u=find(i),v=find(n+j);
      				if(u==v){
      					tag[u]=1;
      				}
      				else{
      					fa[u]=v,tag[v]|=tag[u];
      				}
      			}
      		}
      	}
      //	for(int i=1;i<=n;i++){
      //		cout<<s[i]<<'\n';
      //	}
      	int Ans=0;
      	for(int i=1;i<=n+m;i++){
      		if(find(i)==i&&e[i].size()){
      //			cout<<i<<'\n';
      			if(tag[i]){
      				cnt=ans=0;
      				dfs1(i);
      				Ans=max(Ans,ans);
      			}
      			else{
      				cnt=lfn=ans=0;
      				dfs2(i,0);
      				for(int j=1;j<=lfn;j++){
      					int u=lf[j];
      					if(u<=n){
      						for(int i=1;i<=m;i++){
      							if(s[u][i]=='k'&&f[u][i]--==1){
      								ans--;
      							}
      						}
      					}
      					else{
      						for(int i=1;i<=n;i++){
      							if(s[i][u-n]=='k'&&f[i][u-n]--==1){
      								ans--;
      							}
      						}
      					}
      					Ans=max(Ans,ans);
      					if(u<=n){
      						for(int i=1;i<=m;i++){
      							if(s[u][i]=='k'&&++f[u][i]==1){
      								ans++;
      							}
      						}
      					}
      					else{
      						for(int i=1;i<=n;i++){
      							if(s[i][u-n]=='k'&&++f[i][u-n]==1){
      								ans++;
      							}
      						}
      					}
      				}
      			}
      			for(int j=1;j<=cnt;j++){
      				int u=hp[j];
      				if(u<=n){
      					for(int i=1;i<=m;i++){
      						f[u][i]=0;
      					}
      				}
      				else{
      					for(int i=1;i<=n;i++){
      						f[i][u-n]=0;
      					}
      				}
      			}
      		}
      	}
      	cout<<Ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. 游戲

      發現每個棋子是獨立的,考慮算出 \(sg_{i,j}\) 表示棋子初始在 \((i,j)\) 時的 \(SG\) 值,將所有棋子的 \(SG\) 值異或起來就是總的 \(SG\) 值。

      發現 \(sg_{i+1,j}\) 不受 \(sg_{i,j}\) 影響,于是倒序枚舉每一行。然后對每一行進行分類討論。記行號為 \(t\)

      本行中有障礙

      這一行被這些障礙分成了若干段。于是對于一個位置 \((t,i)\),它只有三種狀態:

      1. \((t-1,i)\) 下來,可以往左、往右或往下走。

      2. \((t,i-1)\) 過來,可以往右或往下走。

      3. \((t,i+1)\) 過來,可以往左或往下走。

      于是我們考慮預處理出 \(f_{0,i}\) 表示當前只可以往左或往下走時 \((t,i)\)\(SG\) 值,\(f_{1,i}\) 表示當前可以往右或往下走時 \((t,i)\)\(SG\) 值,于是 \(sg_{t,i}=\operatorname{mex}(f_{0,i-1},f_{1,i+1},sg_{t+1,i})\)

      本行中沒有障礙

      考慮棋子初始在 \((t,i)\),如果第一步先往左走到了 \((t,i-1)\),那么就不能再往右走了,于是 \((t,i-1)\)\(SG\) 值需要 \((t,i-2)\)\(SG\) 值,進一步需要 \((t,i-3)\)\(SG\) 值……以此類推,我們最終需要的是 \((t,i+1)\)\(SG\) 值,此時只能往下走了,是顯然的。但是這樣我們單次求的時間復雜度是 \(O(m)\) 的,考慮優化。考慮從 \(i-1\) 一路走到 \(i+1\) 的過程,大概是這個樣子:

      C1

      \(sg_{i,j}\) 的取值范圍是 \([0,3]\),于是我們可以預處理出圖中打勾的兩個部分。

      具體地,定義數組 \(g_{0/1/2/3,j,i}\)

      • \(g_{0,j,i}\) 表示 \((t,1)\)\(SG\) 值為 \(j\),棋子從 \(i\) 移動到 \(1\)\((t,i)\)\(SG\) 值。

      • \(g_{1,j,i}\) 表示 \((t,m)\)\(SG\) 值為 \(j\),棋子從 \(i\) 移動到 \(m\)\((t,i)\)\(SG\) 值。

      • \(g_{2,j,i}\) 表示 \((t,i)\)\(SG\) 值為 \(j\),棋子從 \(1\) 移動到 \(i\)\((t,1)\)\(SG\) 值。

      • \(g_{3,j,i}\) 表示 \((t,i)\)\(SG\) 值為 \(j\),棋子從 \(m\) 移動到 \(i\)\((t,m)\)\(SG\) 值。

      于是就可以對每個點進行 \(O(1)\) 計算了。總時間復雜度 \(O(\sum nm)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=2e3+5;
      int T,n,m,sg[maxn][maxn],f[2][maxn],g[4][4][maxn];
      string s[maxn];
      il int mex(int a=-1,int b=-1,int c=-1){
      	for(int i=0;;i++){
      		if(i!=a&&i!=b&&i!=c){
      			return i;
      		}
      	}
      }
      il void solve1(int t){
      	#define gt(i) ((i)>m?(i)-m:(i))
      	memset(f,-1,sizeof(f));
      	int _1=1;
      	while(s[t][_1]!='#'){
      		_1++;
      	}
      	for(int l=_1,r;l<m+_1;l=r){
      		r=l+1;
      		while(s[t][r]!='#'){
      			r++;
      		}
      		if(r==l+1){
      			continue;
      		}
      		f[0][l+1]=mex(sg[t+1][gt(l+1)]);
      		for(int i=l+2;i<r;i++){
      			f[0][i]=mex(f[0][i-1],sg[t+1][gt(i)]);
      		}
      		f[1][r-1]=mex(sg[t+1][gt(r-1)]);
      		for(int i=r-2;i>l;i--){
      			f[1][i]=mex(f[1][i+1],sg[t+1][gt(i)]);
      		}
      		for(int i=l+1;i<r;i++){
      			sg[t][gt(i)]=mex(f[0][i-1],f[1][i+1],sg[t+1][gt(i)]);
      		}
      	}
      	#undef gt
      }
      il void solve2(int t){
      	if(m==1){
      		sg[t][1]=mex(sg[t+1][1]);
      		return ;
      	}
      	for(int i:{0,1,2,3}){
      		g[0][i][1]=g[1][i][m]=g[2][i][1]=g[3][i][m]=i;
      	}
      	for(int i=2;i<=m;i++){
      		for(int j:{0,1,2,3}){
      			g[0][j][i]=mex(g[0][j][i-1],sg[t+1][i]);
      		}
      	}
      	for(int i=m-1;i;i--){
      		for(int j:{0,1,2,3}){
      			g[1][j][i]=mex(g[1][j][i+1],sg[t+1][i]);
      		}
      	}
      	for(int i=2;i<=m;i++){
      		for(int j:{0,1,2,3}){
      			g[2][j][i]=g[2][mex(j,sg[t+1][i-1])][i-1];
      		}
      	}
      	for(int i=m-1;i;i--){
      		for(int j:{0,1,2,3}){
      			g[3][j][i]=g[3][mex(j,sg[t+1][i+1])][i+1];
      		}
      	}
      	for(int i=1;i<=m;i++){
      		int l,r;
      		if(i<m){
      			int tmp=g[3][mex(sg[t+1][i+1])][i+1];
      			if(i==1){
      				l=tmp;
      			}
      			else{
      				l=g[0][mex(tmp,sg[t+1][1])][i-1];
      			}
      		}
      		else{
      			l=g[0][mex(sg[t+1][1])][i-1];
      		}
      		if(i>1){
      			int tmp=g[2][mex(sg[t+1][i-1])][i-1];
      			if(i==m){
      				r=tmp;
      			}
      			else{
      				r=g[1][mex(tmp,sg[t+1][m])][i+1];
      			}
      		}
      		else{
      			r=g[1][mex(sg[t+1][m])][i+1];
      		}
      		sg[t][i]=mex(l,r,sg[t+1][i]);
      	}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--){
      		cin>>n>>m;
      		for(int i=1;i<=n;i++){
      			cin>>s[i];
      			s[i]=" "+s[i]+s[i];
      		}
      		for(int i=1;i<=n+1;i++){
      			for(int j=1;j<=m;j++){
      				sg[i][j]=-1;
      			}
      		}
      		for(int i=n;i;i--){
      			for(int j=1;j<=m;j++){
      				if(s[i][j]=='#'){
      					solve1(i);
      					goto togo;
      				}
      			}
      			solve2(i);
      			togo:;
      		}
      		int ans=0;
      		for(int i=1;i<=n;i++){
      			for(int j=1;j<=m;j++){
      				if(s[i][j]=='B'){
      					ans^=sg[i][j];
      				}
      			}
      		}
      		cout<<(ans?'A':'B')<<'\n';
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      D. 公司

      2025CSP-S模擬賽39

      A B C D Sum Rank
      100 0 30 20 150 10/19

      A. poohfrog

      直接 bfs 即可,時間復雜度 \(O(nmk)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=6e6+5,inf=1e9;
      const int dx[]={-1,1,0,0,0,0};
      const int dy[]={0,0,-1,1,0,0};
      const int dz[]={0,0,0,0,-1,1};
      int n,m,kk,xx,yy,zz,hd=1,tl=0,dep[185][185][185];
      bool vis[185][185][185];
      char s[185][185][185];
      struct node{
      	int x,y,z;
      	node(int x=0,int y=0,int z=0):x(x),y(y),z(z){}
      }q[maxn];
      int main(){
      //	freopen("ex_poohfrog.in","r",stdin);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>kk>>xx>>yy>>zz;
      	for(int k=1;k<=kk;k++){
      		for(int i=1;i<=n;i++){
      			cin>>s[k][i]+1;
      		}
      	}
      	memset(dep,0x3f,sizeof(dep));
      	vis[xx][yy][zz]=1,dep[xx][yy][zz]=0;
      	q[++tl]=node(xx,yy,zz);
      	while(hd<=tl){
      		node u=q[hd++];
      		int x=u.x,y=u.y,z=u.z;
      //		cout<<x<<' '<<y<<' '<<z<<'\n';
      		for(int i=0;i<=5;i++){
      			int nx=x+dx[i],ny=y+dy[i],nz=z+dz[i];
      			if(nx&&nx<=n&&ny&&ny<=m&&nz&&nz<=kk&&!vis[nx][ny][nz]&&s[nz][nx][ny]=='.'){
      				vis[nx][ny][nz]=1,dep[nx][ny][nz]=dep[x][y][z]+1;
      				q[++tl]=node(nx,ny,nz);
      			}
      		}
      	}
      	int ans=inf;
      	for(int i=1;i<=n;i++){
      		for(int j=1;j<=m;j++){
      			ans=min(ans,dep[i][j][kk]);
      		}
      	}
      	cout<<ans*2;
      //	cerr<<'\n'<<clock()*1.0;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 數學題

      C. 貨物運輸

      D. 士兵游戲

      posted @ 2025-08-15 17:07  zhangxy__hp  閱讀(55)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 天天爽夜夜爽人人爽曰| 男女xx00上下抽搐动态图| 久久综合狠狠综合久久激情| 亚洲国产精品成人无码区| 色噜噜亚洲精品中文字幕| 亚洲色大成网站www在线| 亚洲第一区二区国产精品| 亚洲av影院一区二区三区| 日韩有码中文在线观看| 97久久精品人人澡人人爽| 亚洲色大成网站WWW国产| 99精品国产中文字幕| 国产精品一二三区蜜臀av| 在线中文一区字幕对白| 精品无码人妻一区二区三区| 亚洲自拍偷拍中文字幕色| 国产成人毛片无码视频软件| 久久免费精品国自产拍网站| 蜜桃臀av一区二区三区| 亚洲av第一区二区三区| 国产午夜在线观看视频播放| 日本一区二区三区四区黄色| 亚洲精品色一区二区三区| 亚洲熟女综合色一区二区三区 | 久久青草国产精品一区| 国产精品一国产精品亚洲| 精品伊人久久久香线蕉| 无码人妻一区二区三区AV| 国产精品 第一页第二页| 国产精品无码aⅴ嫩草| 蜜臀一区二区三区精品免费| 成人又黄又爽又色的视频| 在线亚洲高清揄拍自拍一品区| 国产毛片子一区二区三区| 人妻丝袜AV中文系列先锋影音| 亚洲精品久久国产高清| 亚洲一级片一区二区三区| 国产精品一码在线播放| 兴仁县| 欧洲亚洲成av人片天堂网| 人妻影音先锋啪啪AV资源|