我的老师让我先做最后再交,看正确率(即以OI赛制打abc)
 所以我用的小号(… …)
C 卡了老半天才出来,我把题读错了

难度:

A. Seats
题意
给你一个字符串  
     
      
       
       
         S 
        
       
      
        S 
       
      
    S,仅包含 . 和 #,找出子串 #.# 的个数
思路
若下标从 0 0 0 开始,直接枚举 i ∈ [ 0 , n − 3 ] i\in [0,n-3] i∈[0,n−3] 即可
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int ans;
int main(){
	cin>>n>>s;
	for(int i=0;i<n-2;i++){
		if(s[i]=='#'&&s[i+1]=='.'&&s[i+2]=='#'){
			ans++;
		}
	}
	cout<<ans<<endl;
	return 0;
}
 
B. Traveling Takahashi Problem
题意
给你平面上的 n n n 个点,第 i i i 个点坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),现在需要从原点 ( 0 , 0 ) (0,0) (0,0) 出发,按顺序经过每个点,并回到原点 ( 0 , 0 ) (0,0) (0,0),问最终走过的距离。
注:从 ( x i , y i ) (x_i,y_i) (xi,yi) 到 ( x j , y j ) (x_j,y_j) (xj,yj) 的距离是 ( x j − x i ) 2 + ( y j − y i ) 2 \sqrt{(x_j-x_i)^2+(y_j-y_i)^2} (xj−xi)2+(yj−yi)2
思路
记录上次停留的位置,按顺序模拟即可
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
long double ans;
int n;
int sqr(int x){
	return x*x;
}
signed main(){
	cin>>n;
	int curx=0,cury=0;
	for(int i=1;i<=n;i++){
		int a,b;
		cin>>a>>b;
		ans+=sqrt(sqr(a-curx)+sqr(b-cury));
		curx=a,cury=b;
	}
	ans+=sqrt(sqr(curx)+sqr(cury));
	cout<<fixed<<setprecision(20)<<ans<<endl;
	return 0;
}
 
C. Spiral Rotation
题意
有一个  
     
      
       
       
         n 
        
       
         ∗ 
        
       
         n 
        
       
      
        n*n 
       
      
    n∗n 的网格(  
     
      
       
       
         n 
        
       
      
        n 
       
      
    n 为偶数),设  
     
      
       
       
         ( 
        
       
         i 
        
       
         , 
        
       
         j 
        
       
         ) 
        
       
      
        (i,j) 
       
      
    (i,j) 为从上往下数第  
     
      
       
       
         i 
        
       
      
        i 
       
      
    i 行,从左往右数第  
     
      
       
       
         j 
        
       
      
        j 
       
      
    j 列的格子,每格要么是 . 要么是 #
对于 i ∈ { 1 , 2 , . . . , n / 2 } i \in \{ 1,2,\ ..., \ n/2\} i∈{1,2, ..., n/2}:
- 选择数对 ( x , y ) (x,y) (x,y) ,其中 1 ≤ x , y ≤ n + 1 − i 1\le x,y \le n+1-i 1≤x,y≤n+1−i,将 ( y , n + 1 − x ) (y,n+1-x) (y,n+1−x) 的值换为 ( x , y ) (x,y) (x,y)
 - 对于所有符合要求的 ( x , y ) (x,y) (x,y),同时 进行以上操作
 
思路
由 $(y,n+1-x) $ = ( x , y ) (x,y) (x,y) 可得: ( i , j ) (i,j) (i,j) = ( n + 1 − j , i ) (n+1-j,i) (n+1−j,i)
那么共有以下四种情况:
-  
( i , j ) = ( n + 1 − j , i ) (i,j) = (n+1-j,i) (i,j)=(n+1−j,i)
 -  
( n + 1 − j , i ) = ( n + 1 − i , n + 1 − j ) (n+1-j,i)=(n+1-i,n+1-j) (n+1−j,i)=(n+1−i,n+1−j)
 -  
( n + 1 − i , n + 1 − j ) = ( j , n + 1 − i ) (n+1-i,n+1-j)=(j,n+1-i) (n+1−i,n+1−j)=(j,n+1−i)
 -  
( j , n + 1 − i ) = ( i , j ) (j,n+1-i)=(i,j) (j,n+1−i)=(i,j)
 -  
下一次就又回到了第一种
 
所以只要看每一个操作了多少次 $\bmod 4 $ 的余数就可以了
C++ 代码
#include<bits/stdc++.h>
using namespace std;
string s[maxn];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s[i];
		s[i]=" "+s[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int curi=(i>k?n-i+1:i);
			int curj=(j>k?n-j+1:j);
			int cur=min(curi,curj)%4;
			if(cur%4==0){
				cout<<s[i][j];
			}else if(cur%4==1){
				cout<<s[n+1-j][i];
			}else if(cur%4==2){
				cout<<s[n+1-i][n+1-j];
			}else{
				cout<<s[j][n+1-i];
			}
		}
		cout<<endl;
	}
	return 0;
}
 
D. ABA
题意
给你一个字符串 s s s,你要选出三个下标: 1 ≤ i < j < k ≤ ∣ s ∣ 1\le i<j<k\le |s| 1≤i<j<k≤∣s∣,将 s i , s j , s k s_i, s_j,s_k si,sj,sk 拼接,使得拼接起来的字符串是 回文串
思路
对于 26 26 26 个字母,分别记录每种出现在哪些位置,再统一加减
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<int> g[26];
string s;
signed main(){
	int n=sz(s);
	s=" "+s;
	for(int i=1;i<=n;i++){
		g[s[i]-'A'].push_back(i);
	}
	int ans=0;
	for(int i=0;i<26;i++){
		if(g[i].size()==0) continue;
		int sum=g[i][0];
		for(int j=1;j<g[i].size();j++){
			ans+=(j*g[i][j]-sum-j);
			sum+=g[i][j];
		}
	}
	cout<<ans<<endl;
	return 0;
}
 
E. 3 Team Division
题意
共有 n n n 个人,已经分成了 3 3 3 组,第 i i i 个人在 a i a_i ai 组 ( 1 ≤ a i ≤ 3 ) (1 \le a_i \le 3) (1≤ai≤3),权值为 b i b_i bi,你可以重新分组,使得每组的 权值和 相等,且 换组的人数 最少
问最少换组的人数
思路
首先可以想到 d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l] 表示:前 i i i 个里面,第一组权值和为 j j j,第二组权值和为 k k k ,第三组权值和为 l l l
那么如何优化?去掉最后一维
因为前 i i i 个人权值和一定,所以直接用总和减去 j + k j+k j+k 就得到了 l l l
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=2e15;
const int maxn=105;
const int maxk=1505;
int n;
int pos[maxn],v[maxn];
int dp[maxn][maxk][maxk];
int sum[maxn];
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>pos[i]>>v[i];
		sum[i]=sum[i-1]+v[i]; //计算前缀和
	}
	if(sum[n]%3!=0){//特判:只有和为3的倍数才能分成3组
		cout<<-1<<endl;
		return;
	}
	for(int i=0;i<=n;i++){//初始化dp数组
		for(int j=0;j<=sum[i];j++){
			for(int k=0;k<=sum[i]-j;k++){
				dp[i][j][k]=inf;
			}
		}
	}
	dp[0][0][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=sum[i];j++){
			for(int k=0;k<=sum[i]-j;k++){
				if(j>=v[i]){
					dp[i][j][k]=min(dp[i-1][j-v[i]][k]+(pos[i]!=1),dp[i][j][k]);
				}
				if(k>=v[i]){
					dp[i][j][k]=min(dp[i-1][j][k-v[i]]+(pos[i]!=2),dp[i][j][k]);
				}
				if(sum[i]-j-k>=v[i]){
					dp[i][j][k]=min(dp[i-1][j][k]+(pos[i]!=3),dp[i][j][k]);
				}
			}
		}
	}
    int ans=dp[n][sum[n]/3][sum[n]/3];
	if(ans==inf){
		cout<<-1<<endl;
	}else{
		cout<<ans<<endl;
	}
	return 0;
}
                


















