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

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

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

      CSP-S模擬37

      T1:回文(string)

      思路:

      由于本題的數(shù)據(jù)范圍較小,所以可能有多種 \(dp\) 狀態(tài),這里只呈現(xiàn)其中可能較典的兩種外加一種暴搜最優(yōu)解。

      DP1:

      我們設 \(f_{i,j,x,y}\) 表示使用 \(a\) 串的 \(i\) ~ \(j\)\(b\) 串的 \(x\) ~ \(y\) 能否拼成一個回文串。

      首先考慮原始狀態(tài)是什么樣的。顯然原始狀態(tài)有三種大情況: \(a,b\) 中的單個字符,\(a,b\) 中相鄰的兩個相同的字符以及 \(a,b\) 串中相同的字符。這些顯然都是初始能構成回文串的字符。

      然后再考慮轉移。顯然有四種轉移方式:\(a\) 串自己左右擴展, \(b\) 串自己左右擴展, \(a\) 串左端與 \(b\) 串右端匹配, \(a\) 串右端與 \(b\) 串左端匹配。

      最后我們枚舉每個串截取的長度,然后枚舉起點,計算出終點。若 \(f_{i,j,x,y}\)\(1\) ,則 \(ans=max(ans,lena+lenb)\)

      \(O(Tn^4)\) 的時間復雜度。跑得還是比較快的。

      代碼:

      $code$
      #include<iostream>
      #include<cstring>
      using namespace std;
      int T,n,m,ans,f[55][55][55][55];
      string a,b;
      int main(){
      	freopen("string.in","r",stdin);
      	freopen("string.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>T;
      	while(T--){
      		ans=1;
      		memset(f,0,sizeof(f));
      		cin>>a>>b;
      		a=' '+a;b=' '+b;
      		n=a.size()-1;m=b.size()-1;
      		for(int i=1;i<=n;i++) 
      			for(int j=1;j<=m+1;j++) 
      				f[i][i][j][j-1]=1;
      		for(int j=1;j<=m;j++) 
      			for(int i=1;i<=n+1;i++) 
      				f[i][i-1][j][j]=1;
      		for(int i=1;i<=n;i++) 
      			for(int j=1;j<=m;j++) 
      				if(a[i]==b[j]) 
      					f[i][i][j][j]=1;
      		for(int i=1;i<n;i++){
      			if(a[i]==a[i+1]){
      				for(int j=1;j<=m+1;j++){
      					ans=2;
      					f[i][i+1][j][j-1]=1;
      				}
      			}
      		}
      		for(int j=1;j<m;j++){
      			if(b[j]==b[j+1]){
      				for(int i=1;i<=n+1;i++){
      					ans=2;
      					f[i][i-1][j][j+1]=1;
      				}
      			}
      		}
      		for(int lena=0;lena<=n;lena++){
      			for(int i=1;i<=n-lena+1;i++){
      				int j=i+lena-1;
      				for(int lenb=0;lenb<=m;lenb++){
      					for(int x=1;x<=m-lenb+1;x++){
      						int y=x+lenb-1;
      						if(f[i][j][x][y]){
      							ans=max(ans,lena+lenb);
      							if(i>1&&j<n&&a[i-1]==a[j+1]) f[i-1][j+1][x][y]=1;
      							if(x>1&&y<m&&b[x-1]==b[y+1]) f[i][j][x-1][y+1]=1;
      							if(i>1&&y<m&&a[i-1]==b[y+1]) f[i-1][j][x][y+1]=1;
      							if(x>1&&j<n&&a[j+1]==b[x-1]) f[i][j+1][x-1][y]=1;
      						}
      					}
      				}
      			}
      		}
      		cout<<ans<<'\n';
      	}
      	return 0;
      }//題解方法 (較快) 
      

      DP2:

      我們設 \(f_{i,j,x,y}\) 表示使用 \(a\) 串的 \(i\) ~ \(j\)\(b\) 串的 \(x\) ~ \(y\) 能拼成回文串的最長長度。

      還是先考慮初始狀態(tài),顯然跟上面的是一樣的,不過上述的狀態(tài)一初始值為 \(1\) ,狀態(tài)二、三的初始值為 \(2\) (因為存的是長度嘛)

      然后轉移就是正常的轉移啦~~

      最后取 \(max\) 就好啦~~

      時間復雜度也是 \(O(Tn^4)\) 的,不過跑起來不如上面那個快。

      $code$
      #include<iostream>
      #include<cstring>
      using namespace std;
      int T,m,n,ans,f[55][55][55][55];
      string a,b;
      int main(){
      //	freopen("string.in","r",stdin);
      //	freopen("string.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>T;
      	while(T--){
      		memset(f,0,sizeof(f));
      		cin>>a>>b;
      		a=' '+a;b=' '+b;
      		n=a.size()-1;m=b.size()-1;
      		for(int lena=0;lena<=n;lena++){
      			for(int i=1;i<=n-lena+1;i++){
      				int j=i+lena-1;
      				for(int lenb=0;lenb<=m;lenb++){
      					for(int x=1;x<=m-lenb+1;x++){
      						int y=x+lenb-1;
      						if(lena+lenb==1) f[i][j][x][y]=1;
      						if(lena+lenb==2){
      							if(!lena&&b[x]==b[y]) f[i][j][x][y]=2;
      							else if(!lenb&&a[i]==a[j]) f[i][j][x][y]=2;
      							else if(lena&&lenb&&a[i]==b[x]) f[i][j][x][y]=2;
      						}
      						if(lena+lenb!=f[i][j][x][y]) continue;
      						if(i>1&&j<n&&a[i-1]==a[j+1]) f[i-1][j+1][x][y]=max(f[i-1][j+1][x][y],f[i][j][x][y]+2); 
      						if(x>1&&y<m&&b[x-1]==b[y+1]) f[i][j][x-1][y+1]=max(f[i][j][x-1][y+1],f[i][j][x][y]+2);
      						if(i>1&&y<m&&a[i-1]==b[y+1]) f[i-1][j][x][y+1]=max(f[i-1][j][x][y+1],f[i][j][x][y]+2);
      						if(x>1&&j<n&&b[x-1]==a[j+1]) f[i][j+1][x-1][y]=max(f[i][j+1][x-1][y],f[i][j][x][y]+2);
      					}
      				}
      			}
      		}
      		int ans=0;
      		for(int i=1;i<=n;i++){
      			for(int j=i-1;j<=n;j++){
      				for(int x=1;x<=m;x++){
      					for(int y=x-1;y<=m;y++){
      						ans=max(ans,f[i][j][x][y]);
      					}
      				}
      			}
      		}
      		cout<<ans<<'\n';
      	}
      	return 0;
      }//分討(較慢) 
      

      暴搜:

      聽說或許可以構造數(shù)據(jù) \(hack\) 掉?

      但目前看來的確是最優(yōu)解無疑了。

      我們分別枚舉 \(a,b\) 串的回文中心(記得特判一下回文串長度為偶數(shù)的情況呀),然后跟上面的 \(dp\) 轉移相似,分別向左右暴搜就行了。

      復雜度為 \(O(能過)\)(其實是我不會算??)

      update: 據(jù)本人說這個代碼的時間復雜度是假的,所以請謹慎使用哦~~

      代碼:

      $code$
      #include<iostream>
      using namespace std;
      int T,m,n,ans;
      string a,b;
      inline void dfs(int la,int ra,int lb,int rb,int len){
      	ans=max(ans,len);
      	if(la>=1&&ra<=n&&a[la]==a[ra]) dfs(la-1,ra+1,lb,rb,len+2);
      	if(la>=1&&rb<=m&&a[la]==b[rb]) dfs(la-1,ra,lb,rb+1,len+2);
      	if(lb>=1&&ra<=n&&b[lb]==a[ra]) dfs(la,ra+1,lb-1,rb,len+2);
      	if(lb>=1&&rb<=m&&b[lb]==b[rb]) dfs(la,ra,lb-1,rb+1,len+2);
      
      }
      int main(){
      //	freopen("string.in","r",stdin);
      //	freopen("string.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>T;
      	while(T--){
      		ans=0;
      		cin>>a>>b;
      		a=' '+a;b=' '+b;
      		n=a.size()-1;m=b.size()-1;
      		for(int i=1;i<=n+1;i++){
      			for(int j=1;j<=m+1;j++){
      				dfs(i-1,i,j-1,j,0);
      				if(i!=n+1) dfs(i-1,i+1,j-1,j,1);
      				if(j!=m+1) dfs(i-1,i,j-1,j+1,1);//回文長度為偶數(shù) 
      			}
      		}
      		cout<<ans<<'\n';
      	}
      	return 0;
      }//暴搜(最快) 
      

      T2:數(shù)排列(perm)

      思路:

      嘿,有個 \(O(n^3)\) 的做法沒聽,當時光顧著笑(一些不明事物)了。這里只提供 \(O(n^2)\) 的做法。

      我們設 \(f_{i,j}\) 表示數(shù)字 \(i\) 放到 \(j\) 的位置上的合法方案數(shù),直接枚舉 \(i-1\) 的位置,然后再前/后綴和優(yōu)化一下撒~~

      代碼:

      $code$
      #include<iostream>
      using namespace std;
      const int N=2025,mod=1e9+7;
      int n,s[N],f[N][N],ans;
      int main(){
      	freopen("perm.in","r",stdin);
      	freopen("perm.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>n;
      	f[0][1]=1;
      	for(int i=1;i<n;i++) cin>>s[i];
      	for(int i=1;i<n;i++){
      		if(s[i]==1) for(int j=2;j<=i+1;j++) f[i][j]=(f[i][j-1]+f[i-1][j-1])%mod;//i放到j位置的方案數(shù)等價于i-1放到所有j-1及以前位置的方案數(shù)加和
      		else for(int j=i;j>=1;j--) f[i][j]=(f[i][j+1]+f[i-1][j])%mod;
      	}
      	for(int i=1;i<=n;i++) ans=(ans+f[n-1][i])%mod;
      	cout<<ans<<'\n';
      	return 0;
      }//O(n^2)
      

      T3:樹上的背包(knapsack)

      思路:

      這里提供根號分治和折半搜索兩種思路。

      折半搜索:

      對于每一次查詢,我們把該節(jié)點及其祖先節(jié)點單獨記錄下來,這樣就轉化為了一個簡單問題:在一堆物品里選代價不超過 \(L\) 且價值最大的物品。不過千萬不要被題目的背包限制住思維,考慮折半搜索。

      我們先來淺淺算一下時間復雜度。每個節(jié)點的深度為 \(log~ _n\) (顯然這是一顆二叉樹),所以折半搜的時間復雜度為 \(2^{ \frac{log_n}{2}}\),轉化一下其實就是 \(\sqrt n\)。再算上多測那就是 \(O(q \sqrt n)\) 。顯然可過,不過跑得不大快,而且碼量相對較大就是了。(相比于根號分治來說)

      代碼:

      $code$
      #include<iostream>
      #include<algorithm>
      #include<cstring>
      #define int long long
      using namespace std;
      const int N=1e5+5;
      int n,Q,x,L,cnt,tot1,tot2,ans,v[N],w[N],vl[N],wei[N];
      struct flower{
      	int val,weight;
      	bool operator<(const flower &css)const{
      		if(weight!=css.weight) return weight<css.weight;
      		else return val<css.val;
      	}
      }a[N],s1[N],s2[N];
      inline void dfs1(int pos,int weight,int val){
      	if(weight>L) return ;
      	if(pos==cnt/2+1){
      		s1[++tot1]={val,weight};
      		return ;
      	}
      	dfs1(pos+1,weight,val);
      	dfs1(pos+1,weight+a[pos].weight,val+a[pos].val);
      }
      inline void dfs2(int pos,int weight,int val){
      	if(weight>L) return ;
      	if(pos==cnt+1){
      		s2[++tot2]={val,weight};
      		return ;
      	}
      	dfs2(pos+1,weight,val);
      	dfs2(pos+1,weight+a[pos].weight,val+a[pos].val);
      }
      signed main(){
      	freopen("knapsack.in","r",stdin);
      	freopen("knapsack.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>n;
      	for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
      	cin>>Q;
      	while(Q--){
      		tot1=tot2=ans=cnt=0;
      		cin>>x>>L;
      		a[++cnt]={0,0};
      		while(x){
      			a[++cnt]=(flower){v[x],w[x]};
      			x/=2;
      		}
      		dfs1(1,0,0);
      		dfs2(cnt/2+1,0,0);
      		sort(s1+1,s1+tot1+1);
      		sort(s2+1,s2+tot2+1);
      		for(int i=1;i<=tot2;i++) s2[i].val=max(s2[i].val,s2[i-1].val);
      		for(int i=1,j=tot2;i<=tot1;i++){
      			while(j&&s2[j].weight+s1[i].weight>L) j--;
      			if(s1[i].weight+s2[j].weight<=L) ans=max(ans,s1[i].val+s2[j].val);
      		}
      		cout<<ans<<'\n';
      	}
      	return 0;
      }//折半搜 (慢) 
      /*
      3
      1 2
      2 3
      3 4
      3
      1 1
      2 5
      3 5
      
      15
      123 119
      129 120
      132 112
      126 109
      118 103
      115 109
      102 100
      130 120
      105 105
      132 115
      104 102
      107 107
      127 116
      121 104
      121 115
      8
      8 234
      9 244
      10 226
      11 227
      12 240
      13 237
      14 206
      15 227
      
      */
      

      根號分治:

      嗨,一種優(yōu)雅的暴力,我覺得沒啥難理解的地方,就不展開啦~~

      代碼:

      $code$
      #include<iostream>
      #include<cstring>
      using namespace std;
      const int N=1e5+5,maxn=511;
      int n,x,l,Q,dp[520][N];
      struct flower{
      	int v,w;
      }a[N];
      inline int work(int x,int l){
      	if(l<0) return -1e9;
      	if(x<=maxn) return dp[x][l];
      	return max(work(x>>1,l),work(x>>1,l-a[x].w)+a[x].v);
      }
      int main(){
      //	freopen("knapsack.in","r",stdin);
      //	freopen("knapsack.out","w",stdout);
      	ios::sync_with_stdio(false);
      	cin>>n;
      	for(int i=1;i<=n;i++) cin>>a[i].v>>a[i].w;
      	for(int i=1;i<=min(maxn,n);i++){
      		if(i>>1) memcpy(dp[i],dp[i>>1],sizeof(dp[i]));
      		for(int j=N-5;j>=a[i].w;j--){
      			dp[i][j]=max(dp[i][j],dp[i][j-a[i].w]+a[i].v);
      		}
      	}
      	cin>>Q;
      	while(Q--){
      		cin>>x>>l;
      		cout<<work(x,l)<<'\n';
      	}
      	return 0;
      }
      

      后言:

      感謝gyh提醒。

      祝阿聯(lián)節(jié)日快樂呀~~

      posted @ 2025-10-24 22:09  晏清玖安  閱讀(13)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 四虎国产精品永久入口| 国产熟女精品一区二区三区| 色香欲天天影视综合网| 99精产国品一二三产品香蕉| 中文字幕va一区二区三区| 丁香婷婷综合激情五月色| 亚洲综合av永久无码精品一区二区 | 柠檬福利第一导航在线| 日韩精品无码一区二区三区视频| 国产无套护士在线观看| 性欧美vr高清极品| 国产成人综合亚洲欧美日韩 | 欧美日韩精品一区二区三区高清视频 | 国产精品国产三级国产试看| 亚洲中文字字幕精品乱码| 中文有无人妻VS无码人妻激烈| 国产女同一区二区在线| 亚洲精品在线二区三区| 成人做爰视频www| www国产成人免费观看视频| 日本高清在线播放一区二区三区| 天堂va亚洲va欧美va国产| 九九成人免费视频| av无码精品一区二区乱子| 亚洲中文字幕精品第三区| 国产一区二区黄色在线观看 | 精品乱码一区二区三四五区| 精品一区二区三区无码视频| 亚洲免费人成在线视频观看| 肉大捧一进一出免费视频| 久久er热在这里只有精品66| 亚洲日韩国产精品第一页一区 | yyyy在线在片| 色欲狠狠躁天天躁无码中文字幕 | 亚洲色欲在线播放一区| 国内精品久久黄色三级乱| 国产精品香港三级国产av| 大又大又粗又硬又爽少妇毛片| 亚洲丰满熟女一区二区v| 色婷婷综合久久久久中文一区二区| 久草热在线视频免费播放|