• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
magicat
博客园    首页    新随笔    联系   管理    订阅  订阅
2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite GCHMAD

2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite

目录
  • 2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite
    • VP 情况
    • G - Let Them Eat Cake
    • C - Catch You Catch Me
    • H - Life is Hard and Undecidable, but...
    • M - Rock-Paper-Scissors Pyramid
    • A - Ban or Pick, What's the Trick
    • D - Gambler's Ruin

VP 情况

队友告诉我题意很顺利过了两签到,对着C虚空写法,搞了一个if(n=3)while(1)的样例发现构造假了,然后马上过了,但是罚时很多然后队友过了石头剪刀布,读了A,很快想到了dp和转移方程,但不知道怎么转移好,最后结束比赛了,看了大家用记忆化搜索竟然这么好些,然后补了DM,这个D我想了很久,一直不懂怎么枚举和三分这个赔率,写了好几个版本,直到今天终于想明白了。
image

G - Let Them Eat Cake

每轮操作删掉一半的数,已得知操作次数最多只有 \(\log n\) 轮,直接模拟

int n;
const int N = 1e5 + 10;
 
void solve()
{
	cin>>n;
	int res = 0;
	vector<int> a, b;
	for(int i = 1; i <= n; i++)
	{
		int x;	cin>>x;
		b.push_back(x);
	}
	int sz = n;
	while(sz != 1)
	{
		res++;
		a = b;
		b.clear();
		int m = a.size();
		for(int i = 0; i < m; i++)
		{
			// cout<<a[i]<<"  ";
			// if(i - 1 >= 0)
			// 	cout<<a[i - 1]<<" ";
			// if(i + 1 < m)
			// 	cout<<a[i + 1]<<" ";
			// cout<<'\n';
			bool ok = false;
			if(i - 1 >= 0 && a[i - 1] > a[i])
			{
				ok = true;
			}
 
			if(i + 1 < m && a[i + 1] > a[i])
				ok = true;
			if(!ok)
				b.push_back(a[i]);
		}
		sz = b.size();
	}
	cout<<res<<'\n';
}

C - Catch You Catch Me

对于1的儿子,其答案是以其儿子为根子树的深度

int n;
const int N = 1e5 + 10;
 
int dep[N], f[N];
vector<int> e[N];
void dfs(int u, int from)
{
	dep[u] = dep[from] + 1;
	f[u] = dep[u];
	for(auto v : e[u])
	{
		if(v == from)	continue;
		dfs(v, u);
		f[u] = max(f[u], f[v]);
	}
}
void solve()
{
	cin>>n;
	for(int i = 1; i < n; i++)
	{
		int u, v;	cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1, 0);
	long long res = 0;
	for(auto v : e[1])
	{
		res = res + f[v] - 1;
	}
	cout<<res<<'\n';
}

H - Life is Hard and Undecidable, but...

构造方式见代码

ll k;
int dx[] = {1, 1};
int dy[] = {1, 0};
int res[310][310];
void solve()
{
	cin>>k;
	int x = 1, y = 1;
	for(int i = 1; i <= 2 * k; i++)
	{
		x = x + dx[0];
		y = y + dy[0];
		res[x][y] = 1;
	} 	
	int n = 0;
	for(int i = 1; i <= 300; i++)
		for(int j = 1; j <= 300; j++)
			n += res[i][j];
	cout<<n<<'\n';
	for(int i = 1; i <= 300; i++)
		for(int j = 1; j <= 300; j++)
			if(res[i][j] == 1)
				cout<<i<<" "<<j<<'\n';
}

M - Rock-Paper-Scissors Pyramid

观察出有单调栈的特点,根据特点直接去模拟单调栈

const int N = 1e6 + 10;
typedef long long ll;
int n, a[N];
void solve()
{
    string s;   cin>>s;
    n = s.size();
    s = "?" + s;
    for(int i = 1; i <= n; i++)
    {
        if(s[i] == 'S') 
            a[i] = 0;
        else if(s[i] == 'P')    
            a[i] = 1;
        else 
            a[i] = 2;
    }
    stack<int> stk; stk.push(a[1]);
    for(int i = 2; i <= n; i++)
    {
        while(!stk.empty() && a[i] == (stk.top() - 1 + 3) % 3)
            stk.pop();
        stk.push(a[i]);        
    }
    while(stk.size() > 1)
        stk.pop();
    if(stk.top() == 0)
        cout<<"S";
    else if(stk.top() == 1)
        cout<<"P";
    else 
        cout<<"R";
    cout<<'\n';
}

A - Ban or Pick, What's the Trick

轮流操作,我可以选择选一个我方能力值最大的英雄,也可以禁掉对方能力值最大的英雄

\(f_{pos,i,j}\)状态就是第 \(pos\) 轮,A选了 \(i\) 个英雄,\(B\) 选了 \(j\) 个英雄,而双方禁用的英雄数量是可以确定的,用记忆化搜索写就行

const int N = 2e5 + 10;
 
typedef long long ll;
 
ll n, k;
ll a[N], b[N];
ll f[2 * N][11][11], tmp;
//  第 pos 次操作, A 选了 j 个, B 选了 p 个
ll dfs(int pos, int i, int j)
{
    if(pos == 2 * n) return 0;
    int dela = i + pos / 2 - j;
    int delb = j + (pos + 1) / 2 - i;
    if(f[pos][i][j] != tmp)
        return f[pos][i][j];
    ll res;
    if(pos % 2 == 0)
    {
        res = -1e18;
        if(dela + 1 <= n && i + 1 <= k)
            res = max(dfs(pos + 1, i + 1, j) + a[dela + 1], res);
        res = max(dfs(pos + 1, i, j), res);
    }
    else
    {
        res = 1e18;
        if(delb + 1 <= n && j + 1 <= k)
            res = min(dfs(pos + 1, i, j + 1) - b[delb + 1], res);
        res = min(dfs(pos + 1, i, j), res);
    }
    f[pos][i][j] = res;
    return res;
}
 
void solve()
{
    cin>>n>>k;
    for(int i = 1; i <= n; i++)
        cin>>a[i];
    for(int i = 1; i <= n; i++)
        cin>>b[i];
    sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + n);
    reverse(a + 1, a + 1 + n);
    reverse(b + 1, b + 1 + n);
    memset(f, 0x3f, sizeof f);
    tmp = f[0][0][0];
    cout<<dfs(0, 0, 0)<<'\n';
    // cout<<f[1][0][0]<<'\n';
}

D - Gambler's Ruin

选择枚举一个队的赔率,三分另一个队的赔率

  1. 将两队预测胜率从小到大排序
  2. 前缀和处理
  3. 枚举A队赔率
  4. 三分另一队赔率

这个我很快想到了解法,但是一直不知道怎么处理1,2操作,写了好多个版本一直过不了样例,过了1周再写就过了

typedef long long ll;
 
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
 
map<double, ll> mp;
int n, m;
vector<pair<double, ll>> a, b;
ll sx[N], sy[N];
double res;
double f(int idx, int idy)
{
    double s1 = 1.0 * a[idx].first * sx[idx];
    double s2 = 1.0 * b[idy].first * sy[idy];    
    return 1.0 * sx[idx] + sy[idy] - max(s1, s2); 
}
void work(int idx)
{
    int l = 0, r = m - 1;
    while(l < r)
    {
        int lmid = l + (r - l) / 3;
        int rmid = r - (r - l) / 3;
        double fl = f(lmid, idx), fr = f(rmid, idx);
        if(fl <= fr)
            l = lmid + 1;
        else r = rmid - 1;
        res = max({fl, fr, res});
        // cout<<l<<" "<<r<<'\n';
    }
}
void solve()
{       
    cin>>n;
    for(int i = 1; i <= n; i++)
    {
        double p;   ll c;   cin>>p>>c;
        mp[p] += c;
    }
    a.push_back({0, 0});
    b.push_back({0, 0});
    for(auto [x, y] : mp)
    {
        if(x != 0.0)
            a.push_back({1.0 / x, y});
        if(x != 1.0)
            b.push_back({1.0 / (1.0 - x), y});
    }
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    n = a.size(), m = b.size();
    for(int i = 0; i < n; i++)
    {
        sx[i] = a[i].second;
        if(i >= 1)  sx[i] += sx[i - 1];
    }
    for(int i = 0; i < m; i++)
    {
        sy[i] = b[i].second;
        if(i >= 1)  sy[i] += sy[i - 1];
    }
    for(int i = 0; i < n; i++)
        work(i);
    cout<<fixed<<setprecision(10)<<res<<'\n';
    return;
}

本文来自博客园,作者:magicat,转载请注明原文链接:https://www.cnblogs.com/magicat/p/17735234.html

posted on 2023-09-28 11:01  magicat  阅读(97)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3