CSP模拟3

A. 回文

\(20\) 多分的纯暴力搜索,\(A_{i,j} = A_{i-1,j+1}\) 可以判完回文直接递推出路径数,共 \(42 \text{pts}\)

正解 \(DP\)

回文可以转化一下思路,两个人分别从 \((1,1),(n,m)\) 出发,走的路径相同的方案数。

设计 \(dp[i][j][s][t]\) 为第一个人在 \((i,j)\) 位置,第二个人在 \((s,t)\) 位置的方案数。

转移要注意步数相同,即 \(i + j - 2 = n + m - s - t\)

因为我们每走一步会使你的坐标 \(x + y\) 加上 \(1\),又因为我们坐标都是从 \(1\) 开始的,所以第一个人路径长度就是 \(x + y - 2\)

第二个人由于是从 \(n + m\) 开始,不太一样。

所以就可以压掉一维,\(t = n + m + 2 - s - i - j\)(好长)。

最后要考虑一下回文有两种情况,一种是长度为奇数,即最后两个人走到同一个位置;另一种长度为偶数,即二者相邻的状态,这种要考虑两种相邻的情况(上下和左右)。

这个思路来自sandom学长的博客,稍微解释地详细了一下。

这道题最坑的就是模数 \(993244853\)!!!!!!

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
using namespace std;

const int N = 505;
const int Mod = 993244853; 

int n,m;

char a[N][N];

int dp[N][N][N];

long long ans;

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)
            cin >> a[i][j];
            
    if(a[1][1] == a[n][m])
        dp[1][1][n] = 1;
    else {
        cout << "0";
        return 0;
    }

    for(int i = 1;i <= n; i++) {
        for(int j = 1;j <= m; j++) {
            for(int s = n;s >= 1; s--) {
                int t = n + m + 2 - i - j - s;
  
                if(t < 1 || t > m)
                    continue;

                ans = dp[i][j][s];
                if(a[i][j] == a[s][t])
                    ans = ans + dp[i - 1][j][s + 1] + dp[i - 1][j][s] + dp[i][j - 1][s + 1] + dp[i][j - 1][s];
                dp[i][j][s] = ans % Mod;
            }
        }
    }

    ans = 0;

    for(int i = 1;i <= n; i++) {
        for(int j = 1;j <= m; j++) {
            int s,t;

            s = i,t = j;
            if(i + j + s + t == n + m + 2)
                ans += dp[i][j][s];
  
            s = i + 1,t = j;
            if(i + j + s + t == n + m + 2)
                ans += dp[i][j][s];
            
            s = i,t = j + 1;
            if(i + j + s + t == n + m + 2)    
                ans += dp[i][j][s];
                
            ans %= Mod;
        }
    }

    cout << ans;
    return 0;
}

B. 快速排序

指针看不懂寄

简单看一下题目里给的快速排序。

\(\text{namespace\_std}\) 的快排是以待排区间的第一个数为基准值的,把小于基准值的放在基准值左边,其余的放在基准值右边。

\(nan\) 无论与任何数比较都会返回 \(0\)

所以对于操作序列。

若第一个数是 \(nan\),这次操作不会改变任何一个数的位置;

若第一个数不是 \(nan\),把它后边小于它的数都放在它前面。

Code

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 114514 * 5;

int T,n;

int a[N];
string st;

int To_int(string s) {
	int ans = 0;
	int bit = 1;
	for(int i = s.size() - 1;i >= 0; i--) {
		ans += (s[i] - 48) * bit;
		bit *= 10;
	}
	return ans;
}

deque<int> b;
priority_queue< int,vector<int>,greater<int> > q;

int max_num;

void qsort(int l,int r) {
    if(l >= r) {
        b.push_back(a[l]);
        return ;
    }

    if(!a[l])
        b.push_back(0);
    else if(a[l] >= max_num) {
        while(!q.empty() && q.top() < a[l]) {
            b.push_back(q.top());
            q.pop();
        }

        b.push_back(q.top());
        q.pop();

        max_num = a[l];
    }

    qsort(l + 1,r);
    return ;
}

signed main() {
    ios::sync_with_stdio(false);
    cin >> T;

    while(T--) {
        cin >> n;

        for(int i = 1;i <= n; i++) {
            cin >> st;
            if(st[0] != 'n')
                a[i] = To_int(st);
            else    
                a[i] = 0;
        }

        for(int i = 1;i <= n; i++)
            if(a[i])
                q.push(a[i]);
        
        qsort(1,n);

        for(int i = 0;i < n; i++)
            if(b[i] != 0)
                cout << b[i] << " ";
            else
                cout << "nan ";
        cout << "\n";

        while(!q.empty())
            q.pop();
        while(!b.empty())
            b.pop_back();
        
        max_num = 0;
    }
    
    return 0;
}
posted @ 2023-07-22 21:02  -白简-  阅读(35)  评论(4编辑  收藏  举报