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();
}

浙公网安备 33010602011771号