2024.10.21 CW 模拟赛

题目链接

T2

概率 \(dp\)

考虑从后往前递推, 令 \(f_{i,j}\) 表示后 \(i\) 步, 当前位置为 \(j\) 的概率.

那么显然, \(j \in [n-i+1,n+i-1]\). (因为 \(a_i \in \{-1,1\}\) ,所以在后 \(i\) 步的时候, 前面操作了 \(n-i\) 次, 最多只有可能在 \([n-i+1,n+i-1]\) 这个范围内)

那为什么不从前往后递推呢?

如果考虑从前往后, 不好考虑当前位置对答案的影响.

但如果从后往前考虑, 当前位置对答案的影响就非常简单, 只需要赋值为1即可.

转移就很简单了.

#include "iostream"

using namespace std;

typedef long long ll;

template<typename T>
inline void read(T &x){
    x=0; bool f=1; char ch=getchar();
    while (!isdigit(ch)){
        if (ch=='-') f=!f;
        ch=getchar();
    }
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    x=(f?x:-x);
    return;
}

template<typename T>
void print(T x){
    if (x<0) putchar('-'),x=-x;
    if (x>9) print(x/10);
    putchar(x%10+'0');
    return;
}

const int N=5e3+1,mod=1e9+7;

int n;
int ps,pm;
short a[N];
ll f[2][N<<1];//滚动数组

int main(){
    
    read(n); read(ps);
    for (int i=1;i<=n;++i) read(a[i]);
    
    int dn=n<<1;
    ps=1ll*570000004*ps%mod,pm=(1-ps+mod)%mod;
    
    f[0][n]=1;
    for (int i=1;i<=n;++i){
        
        int x=i&1,y=i&1^1;
        for (int j=n-i+1;j<=n+i-1;++j){
            (f[x][j]+=ps*f[y][j])%=mod;
            (f[x][j+a[n-i+1]]+=pm*f[y][j])%=mod;
        }
        
        for (int j=0;j<=dn;++j) f[y][j]=0;
        
        f[x][n]=1;
    }
    
    int x=n&1;
    for (int i=0;i<=dn;++i) print(f[x][i]),putchar(' ');
    
    return 0;
}

T3

  • 引理: 一个长度为 \(2n\) 的括号串合法, 当且仅当所有左括号的位置能被 \(1,3,5,7...,2n+1\) 偏序.
  • 证明: 不难发现这个形式等价于括号前缀函数 \(\ge 0\).
  • 正解: 令 \(nxt_i\) 表示 \(a_i\) 右侧对应的位置.
    于是我们就可以看成是左括号的位置和 \(1,3,5,7,...,2n+1\) 的匹配.

考虑从前往后扫, 假设遇到 \(i\)\(a_i\) 还没确定, 如果 \(nxt_i\) 的可以选择匹配, 那就拿去匹配.

时间复杂度 \(\mathcal{O}(n \log n)\).

#include "iostream"
#include "set"

using namespace std;

const int N = 2e6 + 10;

template<typename T>
inline void read(T &x) {
	x = 0;
	char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return;
}

int n;
int nxt[N], h[N];
bool ans[N];
set<int> s;

int main() {

	read(n);

	int dn = n << 1;
	for (int i = 1; i <= dn; ++i) {
		int x;
		read(x);
		nxt[h[x]] = i;
		h[x] = i;
	}

	for (int i = 1; i <= n; ++i) s.insert((i << 1) - 1);

	for (int i = 1; i <= dn; ++i) if (nxt[i]) {
			if (!s.empty() and *s.rbegin() >= nxt[i]) {
				s.erase(s.lower_bound(nxt[i]));
				auto x = s.lower_bound(i);
				if (x == s.end()) return puts(":("), 0;
				s.erase(x), ans[i] = ans[nxt[i]] = 1;
			}
		}

	if (!s.empty()) return puts(":("), 0;
	for (int i = 1; i <= dn; ++i) putchar(ans[i] ? '(' : ')');

	return 0;
}
posted @   Steven1013  阅读(3)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示