CSP-S 2021题解

T1
sol.考场上面写的是三分啊!直接挂飞,正解是一个模拟乱做

#include<bits/stdc++.h>
#define MAXN 500005
using namespace std;

int n,m1,m2;
struct node{int L,R;}t[MAXN];
int val[MAXN],ans,sum;

bool operator < (node A , node B){return A.L < B.L;}
set<node>q;


int cal(){
	int now = 0 , cnt = 0;
	set< node > :: iterator it;
	while(q.upper_bound((node){now , 0}) != q.end()){
		it = q.upper_bound((node){now , 0});
		q.erase(it) , cnt++;
		now = t[(*it).R].R;
	}
	return cnt;
	
}

int main(){
	scanf("%d%d%d" , &n , &m1 , &m2) , q.clear();
	for(int i = 1 ; i <= m1 ; i++)scanf("%d%d" , &t[i].L , &t[i].R) , q.insert((node){t[i].L , i});
	for(int i = 1 ; i <= n ; i++)val[i] = val[i - 1] + cal();
	q.clear();
	for(int i = 1 ; i <= m2 ; i++)scanf("%d%d" , &t[i].L , &t[i].R) , q.insert((node){t[i].L , i});
	ans = val[n];
	for(int i = 1 ; i <= n ; i++)sum += cal() , ans = max(ans , val[n - i] + sum);
	cout<<ans<<endl;
	
}

T2.

sol.一开始想了一个线性dp,发现假了,然后再看看\(n <= 500\) , 直接写一个区间dp就好了

\[f[i][j] 表示[i-j]这一段的方案数 , 且(i , j)匹配\\ g[i][j] 表示[i-j]这一段的方案数 , 且(i , j)不匹配\\ check(i,j)表示检测[i-j]这一段能否全部为*\\ check2(i,j)表示能否以(i,j)作为一段合法序列的端点\\ f[i][j] += [check(i + 1 , j - 1) \&\& check2(i , j)](单独成一段)\\ check2(i , j) == 1:\\ f[i][j] += f[i + 1][j - 1] + g[i + 1][j - 1]\\ f[i][j] += \sum_k(f[i + 1][k] + g[i + 1][k]) * check(k + 1 , j - 1)( \ (AS)\ )\\ f[i][j] += \sum_k(f[k][j - 1] + g[k][j - 1]) * check(i + 1 , k - 1)( \ (SA)\ )\\ g[i][j] += \sum_{i < k1 < k2 < j}[check(k1 + 1 , k2 - 1)] * (f[i][k1] + g[i][k1]) * f[k2][j](ASA) \]

做到这,可以发现,你后面那个玩意的转移是\(O(n^4)\)的,但随着k1增大,k2的转移量很小,可以直接在\(O(1)\)内处理好

#include<bits/stdc++.h>
#define MAXN 905
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;

int n,K;
char a[MAXN];
ll f[MAXN][MAXN],g[MAXN][MAXN];

bool check(int L , int R){//判断[L-R]这一段能否全部为* 
	for(int i = L ; i <= R ; i++)if(a[i] == '(' || a[i] == ')')return false;
	return R - L + 1 <= K;
}

bool check2(int L , int R){
	if(a[L] == ')' || a[L] == '*')return false;
	if(a[R] == '(' || a[R] == '*')return false;
	return true;
}

int main(){
	scanf("%d%d" , &n , &K);
	scanf("%s" , a + 1);
	for(int len = 2 ; len <= n ; len++){
		for(int i = 1 ; i + len - 1 <= n ; i++){
			int j = i + len - 1;
			if(check(i + 1 , j - 1) && check2(i , j))f[i][j]++;
			if(check2(i , j)){
			f[i][j] = (f[i][j] + f[i + 1][j - 1] + g[i + 1][j - 1]) % mod;
			for(int k = 1 ; k <= K ; k++)f[i][j] = (f[i][j] + (f[i + 1][j - k - 1] + g[i + 1][j - k - 1]) * check(j - k , j - 1)) % mod;//(AS)
			for(int k = 1 ; k <= K ; k++)f[i][j] = (f[i][j] + (f[i + k + 1][j - 1] + g[i + k + 1][j - 1]) * check(i + 1 , i + k)) % mod;//(SA)
			}
			int sum = 0;
			for(int k2 = i + 2 ; k2 <= K + i + 1 ; k2++)if(check(i + 1 , k2 - 1))sum += f[k2][j];
			g[i][j] = g[i][j] + (f[i][i + 1] + g[i][i + 1]) * sum;
			for(int k1 = i + 2 ; k1 < j ; k1++){
				if(check(i + 1 , k1 - 1))sum = sum - f[k1][j];
				g[i][j] = (g[i][j] + (f[i][k1] + g[i][k1]) * sum) % mod;
				if(check(i + 1 , k1 + K + 1) && k1 + K + 1 < j)sum = sum + f[k1 + K + 1][j];
				
				
				
				
			}
			
			
			//cout<<i<<"   "<<j<<"   "<<f[i][j]<<"  "<<g[i][j]<<endl;
			
		}
	}	
	cout<<(f[1][n] + g[1][n]) % mod<<endl;
	
}

T3.

sol.有个很显然的结论。往左往右你每选一个的对偶的那个数字,一定是一段连在一起的

直接贪心做就好了

#include<bits/stdc++.h>
#define MAXN 6000005
using namespace std;

int T,n,a[MAXN],last[MAXN],zhuan[MAXN];
int len,L,R,dx,dy,vis[MAXN];
char ans[MAXN];


int main(){
	scanf("%d" , &T);
	while(T--){
		scanf("%d" , &n);
		for(int i = 1 ; i <= 2 * n ; i++)scanf("%d" , &a[i]);
		for(int i = 1 ; i <= n ; i++)last[i] = (-1);
		for(int i = 1 ; i <= 2 * n ; i++){
			if(last[a[i]] != (-1))zhuan[i] = last[a[i]] , zhuan[last[a[i]]] = i;
			else last[a[i]] = i;
		}
		for(int i = 1 ; i <= n ; i++)vis[i] = 0;
		dx = dy = zhuan[1];
		vis[a[1]]++;
		L = 2 , R = 2 * n;
		ans[1] = 'L' , ans[2 * n] = 'L';
		for(int i = 2 ; i <= n ; i++){
			if(abs(dx - zhuan[L]) == 1 && !vis[a[L]])ans[i] = 'L' , ans[2 * n - i + 1] = 'L' , dx = zhuan[L] , vis[a[L]]++ , L++;
			else if(abs(dy - zhuan[L]) == 1 && !vis[a[L]])ans[i] = 'L' , ans[2 * n - i + 1] = 'R' , dy = zhuan[L] , vis[a[L]]++ , L++; 
			else if(abs(dx - zhuan[R]) == 1 && !vis[a[R]])ans[i] = 'R' , ans[2 * n - i + 1] = 'L' , dx = zhuan[R] , vis[a[R]]++ , R--;
			else if(abs(dy - zhuan[R]) == 1 && !vis[a[R]])ans[i] = 'R' , ans[2 * n - i + 1] = 'R' , dy = zhuan[R] , vis[a[R]]++ , R--;
			else {dx = (-1);break;}
			if(dx > dy)swap(dx , dy) , ans[2 * n - i + 1] = 'R';
		}
		if(dx != (-1)){
			for(int i = 1 ; i <= 2 * n ; i++)cout<<ans[i];
			cout<<endl;
			continue;
		}
		
		for(int i = 1 ; i <= n ; i++)vis[i] = 0;
		dx = dy = zhuan[2 * n];
		vis[a[2 * n]]++;
		L = 1 , R = 2 * n - 1;
		ans[1] = 'R' , ans[2 * n] = 'L';
		for(int i = 2 ; i <= n ; i++){
			if(abs(dx - zhuan[L]) == 1 && !vis[a[L]])ans[i] = 'L' , ans[2 * n - i + 1] = 'L' , dx = zhuan[L] , vis[a[L]]++ , L++;
			else if(abs(dy - zhuan[L]) == 1 && !vis[a[L]])ans[i] = 'L' , ans[2 * n - i + 1] = 'R' , dy = zhuan[L] , vis[a[L]]++ , L++; 
			else if(abs(dx - zhuan[R]) == 1 && !vis[a[R]])ans[i] = 'R' , ans[2 * n - i + 1] = 'L' , dx = zhuan[R] , vis[a[R]]++ , R--;
			else if(abs(dy - zhuan[R]) == 1 && !vis[a[R]])ans[i] = 'R' , ans[2 * n - i + 1] = 'R' , dy = zhuan[R] , vis[a[R]]++ , R--;
			else {dx = (-1);break;}
			if(dx > dy)swap(dx , dy) , ans[2 * n - i + 1] = 'R';
		}
		if(dx != (-1)){
			for(int i = 1 ; i <= 2 * n ; i++)cout<<ans[i];
			cout<<endl;
			continue;
		}
		
		cout<<-1<<endl;
		
		
		
	}
}

T4

艹,考场上没看,不然60pts就有了,就是一个网络流转对偶图裸题

sol.就【狼抓兔子】

#include<bits/stdc++.h>
#define MAXN 805
#define INF 0x3f3f3f3f
using namespace std;

int n,m,Q;
int a[MAXN][MAXN],b[MAXN][MAXN];
int zhuan(int x , int y){return (x - 1) * m + y;}
int h[MAXN * MAXN],tot,cur[MAXN * MAXN];
int K,S,T;
struct node{int from,to,next,rest;}e[10 * MAXN * MAXN];
void add(int x , int y , int z){
	tot++;
	e[tot].from = x;
	e[tot].to = y;
	e[tot].rest = z;
	e[tot].next = h[x];
	h[x] = tot;
}

int dis[MAXN * MAXN],vis[MAXN * MAXN];
queue<int>q;
bool bfs(){
	memset(vis , 0 , sizeof(vis));
	memset(dis , 0x3f , sizeof(dis));
	for(int i = 0 ; i <= T ; i++)cur[i] = h[i];
	q.push(S) , dis[S] = 0 , vis[S] = 1;
	int now;
	while(!q.empty()){
		now = q.front() , q.pop() , vis[now] = 0;
		for(int i = h[now] ; i != (-1) ; i = e[i].next){
			if(!e[i].rest)continue;
			if(dis[e[i].to] <= dis[now] + 1)continue;
			dis[e[i].to] = dis[now] + 1;
			if(!vis[e[i].to])q.push(e[i].to) , vis[e[i].to] = 1;
		}
	}
	return (dis[T] < INF);
}

int dfs(int now , int low){
	if(now == T)return low;
	int used = low , res;
	for(int i = cur[now] ; i != (-1) ; i = e[i].next , cur[now] = i){
		if(dis[e[i].to] != dis[now] + 1)continue;
		if(!e[i].rest)continue;
		if(res = dfs(e[i].to , min(used , e[i].rest))){
			used -= res;
			e[i].rest -= res;
			e[i ^ 1].rest += res;
			if(!used)break;
		}
	}
	return low - used;
}

int zhuan(int x){
	if(x <= m)return zhuan(1 , x);
	x -= m;
	if(x <= n)return zhuan(x , m);
	x -= n;
	if(x <= m)return zhuan(n , m + 1 - x);
	x -= m;
	return zhuan(n + 1 - x , 1);
}

void init(){
	S = 0 , T = n * m + 1;
	memset(h , -1 , sizeof(h)) , tot = (-1);
	for(int i = 1 ; i <= n ; i++){
		for(int j = 1 ; j < m ; j++){
			add(zhuan(i , j) , zhuan(i , j + 1) , a[i][j]);
			add(zhuan(i , j + 1) , zhuan(i , j) , a[i][j]);
		}
	}
	for(int i = 1 ; i < n ; i++){
		for(int j = 1 ; j <= m ; j++){
			add(zhuan(i , j) , zhuan(i + 1 , j) , b[i][j]);
			add(zhuan(i + 1 , j) , zhuan(i , j) , b[i][j]);
		}
	}
	scanf("%d" , &K);
	int x,y,z;
	for(int i = 1 ; i <= K ; i++){
		scanf("%d%d%d" , &x , &y , &z);
		add((z ? T : S) , zhuan(y) , x) , add(zhuan(y) , (z ? T : S) , x);
	}
	int sum = 0;
	while(bfs()){
		sum += dfs(S , INF);
	}
	cout<<sum<<endl;
	
}

int main(){
	scanf("%d%d%d" , &n , &m , &Q);
	for(int i = 1 ; i < n ; i++)
		for(int j = 1 ; j <= m ; j++)
			scanf("%d" , &b[i][j]);
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j < m ; j++)
			scanf("%d" , &a[i][j]);
	while(Q--)init();
	
	
}
posted @ 2021-10-26 20:49  After_rain  阅读(162)  评论(0)    收藏  举报