6月22日训练感悟

超电磁炮

题目描述

炮姐和n—1个御坂妹妹站在你的面前,你想要通过实验在众多御坂妹妹中找出炮姐。
你发明的装置可以接收超电磁炮,在一次测试中炮姐和所有的御坂妹妹会同时向装置发射电磁炮,而你可以操控装置将电磁炮的能量分为两束,然后分别计算两束能量的能量和。由于炮姐的电磁炮能量远超御坂妹妹(你可以认为大于其它n-1个御坂妹妹的能量之和),所以通过多次测试一定可以找出炮姐,然而装置所能承受的能量是有限的,你需要计算出最多需要测试多少次才可以完成实验,找出真正的炮姐。

样例数据
样例1

输入数据:

2

输出数据:

1
样例2

输入数据:

3

输出数据:

2
题目分析

由于这道题要求最少测试次数,并且要求是分成两组,所以可以马上想到可以通过二分的方法确定炮姐。并且,由于用二分,相当于求N在那两个2的整数幂之间

题目代码
#include<bits/stdc++.h>
using namespace std;
long long ans;
long long n;
signed main(){
	freopen("railgun.in","r",stdin);
	freopen("railgun.out","w",stdout);
	cin>>n;
	for(long long i=1;i<n;i*=2){
		ans++;
	}
	cout<<ans;
}
做题感受

感觉这道题不是很难,方法比较简单粗暴,唯一的细节就是需要将<=改成<​
(已AC)

为美丽的世界献上爆炎

题目描述

在红魔村中,悠悠向惠惠发起了挑战。
桌上有n枚硬币,两人轮流拿硬币。每次可以在区间7中选择一个数字x然后拿走x枚硬币,[0若一方无法再拿取则输掉了游戏,由惠惠先手开始拿硬币。
惠惠和悠悠都是聪明的,现在惠惠想在游戏开始前,请你帮忙判断她是否能够必胜,若她可以必胜则会按照必胜策略和悠悠进行游戏,若不能必胜她就只好作弊来战胜悠悠了。
游戏一共会进行t局,每局游戏都需要你判断胜负。

样例数据
样例1

输入数据:

2
6 1 4
10 3 5

输出数据:

yes
no
题目分析

这道题可以发现,比如说6 1 4 这个样例中,慧慧可以先取1颗石子,这样子,悠悠无论取什么,慧慧都可以取完。
所以如果l=1时,只要把n除(r+1)的余数拿完即可

题目代码
#include<bits/stdc++.h>
using namespace std;
long long t,n,l,r;
signed main(){
	freopen("explosion.in","r",stdin);
	freopen("explosion.out","w",stdout);
	cin>>t;
	for(int i=1;i<=t;i++){
		cin>>n>>l>>r;
		if(l==1){
			if(n%(r+1)==0){
				cout<<"No";
				continue;
			}
			else{
				cout<<"yes";
				continue;
			}
		}
		else{
			int f=n/r;
			int g=n%r;
			if(f%2&&g<l||!f%2&&g>=l){
				cout<<"yes";
				continue;
			}
			else{
				cout<<"no";
				continue;
			}
		}
	}
}
做题感受

这道题是一道思维题,通过找规律来推出公式

错误原因

yes和no 大写了

树和数

题目描述

阿尔德希尔是须弥生论派的学者,他对生物学有很深的研究,同时他也对数学有着浓厚的兴趣。一天他正在化城郭散步,突然想到了下面这个问题:
二叉树是一种树型结构,它的特点是每个节点最多有两棵子树,且左右子树有左右之分,其左右顺序不能颠倒,如下图就是一颗二叉树。

在这里插入图片描述

一颗严格二叉树是指除叶子节点外任何一个节点均有两个子树的二叉树,如下图就是一颗严格二叉树。

在这里插入图片描述

一个表达式可以惟一对应一颗严格二叉树,这个二叉树的叶子节点为数字,其余节点为运算符,如
(1+2)*4-5/7可以对应到下图的一颗严格二叉树中。

在这里插入图片描述

同理这样一颗严格二叉树同样可以对应到一个表达式,现在规定一个表达式的计算顺序为先进行运算等级高的运算,再计算运算等级低的,相同运算级按照从左往右的顺序计算,括号拥有最高的运算等级。
现在将上述的这样一颗二叉树的叶子节点全部去掉,只剩下n个表示符号的节点,如下图所示。

在这里插入图片描述

虽然去掉了叶子节点上的数字,表达式没有具体的结果,但它依然可以表示出运算的顺序,该二叉树对应了(a+b)*C-d/e这样一种运算顺序。现在给你一颗这样的只包含运算符号的二叉树,共有m中不同运算等级的运算符号,运算等级越高计算优先级越高,请你求出它对应的一个表达式中至少需要多少对括号才能使得运算顺序不变。
如上述二叉树同样也对应了((a+b)*c)-d/e和((a+b)*c-d/e)等运算顺序,但(a+b)*c-d/e需要的括号最少,只需要一对括号,若去掉这对括号运算顺序就会发生改变,所以
答案为1。

样例数据
样例1

输入数据:

4 2
2 3 1
4 0 2
0 0 2
0 0 1

输出数据:

1
样例2

输入数据:

4 1
2 3 1
0 0 1
0 4 1
0 0 1

输出数据:

2
题目分析

这道题中要打括号的只能是优先算的,比如(a+b)c中a+b的运算级比c的运算级要小,但是要先算

题目代码
#include <bits/stdc++.h>
const int N = 100010;
int n, m, ans;
int w[N], l[N], r[N];
int main() {
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    cin>>n>>m;
    for (int k = 1; k<= n; k++)
        cin>>l[i]>>r[i]>>w[i];
    for (int k = 1; k<= n; k++) {
        if (l[k]) ans += w[k] >w[l[k]];
        if (r[k]) ans += w[k] >= w[r[k]];
    }
    cout<<ans;
    return 0;
}

做题感受

这道题是一个简单的思维题,需要搞清楚什么时候要加括号
(已AC)

愿此行终抵群星

题目描述

你正乘坐着星穷列车造访寓居宇宙的万象世界,列车进入了一个k维空间。
在这片空间下,每一个点可以看作是一个k维坐标。列车处在(0,0,…,0)点,位于
(81,82,…,sk)有一颗星球正处于“星核引发的危机之中,列车需要前往这颗星球解救上面的文明。假如列车现在的坐标是(x1,X2,…,xk),它可以到达
(x₁+1,x₂,.,xk),(x₁,C₂+1,…,ck),…,(x₁,T₂,…,Ck+1)这k个点中的一个,终点是
(81,82,…,sk)。
然而,这片空间也遭到了反物质军团的入侵,空间中的n个点
(a11,a12,…a1k),(a21,Q22,….a2k),…,(an1,an2,…ank)被反物质军团占领,为了尽快地到达目的星球,需要绕过这些点。
现在请你计算出有多少种不同的方案可以在不经过这n个点的情况下到达目的星球,答案可能很大,请对998244353取模。

样例
样例1

输入数据:

2 0
2 1

输出数据:

3
样例2

输入数据:

2 1
2 2
1 1

输出数据:

2
样例3

输入数据:

3 2
2 2 1
0 0 1
1 2 1

输出数据:

15
题目分析

这道题比较的难,我在考试的时候没有做出来(悲)
他的意思是说在一个拥有k个坐标的地方,有n个地方不能经过。
首先考虑没有不能到达点的情况,此时在二维情况下,即为从(0,0)点走到(a,b)点,只能向上走和向右走,统计方案数。可以发现无论怎么走,我们都会走a+b次,而其中有a向右走,b次向上走,我们要做的其实就是在a+b次操作中选择a次向右走,剩下的向上走,所以答案为C(a,a+b)=(a+b)!/a!b!。
在三维情况下,即为从(0,0,0)走到(a,b,c),可以根据组合意义,得到答案为(a+b+c)!/a!b!c!更高维的情况同理。
然后考虑有限制的情况,即有一些点不能经过,可以发现不能经过的点是不多的,可以作为突破口。我们设f[i]表示到达第i个点的合法方案数,我们可以通过一个简单的容斥来计算f[i]。首先总的方案数是从原点到第i个点的方案数,然后要减去不合法的方案数。不合法的方案会经过很多个给定点,为了避免重复计算,我们可以枚举第一个到达的点j,然后要减去的方案数就是f[j]乘上j到i的方案数。
为了确保dp的顺序是正确的,即在计算点i时,所有可以到达i的点j都在之前已经计算过了,我们可以对所有点进行排序,优先按照第一维,然后第二维,依次类推。这样就可以确保转移的顺序时正确的。
最后我们可以将目标点作为第n+1个点,答案为f[n+1],复杂度O(n²)。

题目代码
#include <bits/stdc++.h>
const int N = 5010, M = 1000000, mod = 998244353;
int m, n;
long long f[N], fac[M], facinv[M], inv[M];
struct point {
    std::array<int, 10> x;

    bool operator < (const point &r) const {
        for (int k = 0; k < m; k++)
            if (x[k] ^ r.x[k]) return x[k] < r.x[k];
        return 0;
    }
    
    long long get_c(const point &r) {
        for (int k = 0; k < m; k++)
            if (r.x[k] < x[k]) return 0ll;
        int sum = 0;
        for (int k = 0; k < m; k++)
            sum += r.x[k] - x[k];
        long long ans = fac[sum];
        for (int k = 0; k < m; k++)
            (ans *= facinv[r.x[k] - x[k]]) %= mod;
        return ans;
    }
}a[N];
inline long long sub(long long x, long long y) {
    return x - y > 0? x - y: x - y + mod;
}
int main() {
    freopen("star.in", "r", stdin);
    freopen("star.out", "w", stdout);
    cin>>m>>n;
    int maxx = 0;
    for (int k = 0; k < m; k++)
        scanf("%d", &a[n + 1].x[k]), maxx = std::max(maxx, a[n + 1].x[k]);
    for (int k = 1; k <= n; k++)
        for (int i = 0; i < m; i++)
            scanf("%d", &a[k].x[i]);
    maxx *= m;
    fac[0] = 1;
    for (int k = 1; k <= maxx; k++)
        fac[k] = (fac[k - 1] * k) % mod;
    inv[1] = 1;
    for (int k = 2; k <= maxx; k++)
        inv[k] = (mod - mod / k) * inv[mod % k] % mod;
    facinv[0] = 1;
    for (int k = 1; k <= maxx; k++)
        facinv[k] = facinv[k - 1] * inv[k] % mod;
    std::sort(a + 1, a + 1 + n);
    for (int k = 1; k <= n + 1; k ++) {
        f[k] = a[0].get_c(a[k]);
        for (int i = 1; i < k; i++)
            f[k] = sub(f[k], f[i] * a[i].get_c(a[k]) % mod);
    }
    cout<<f[n+1];
}
题目总结

这道题是一个难度很高的思维题,里面用到容斥和组合数的知识

比赛总结

这场比赛主要是靠思维解题,大部分只要有思维就很简单就可以解出来。
总体上看,我这次除了大小写的错误,其他没有错

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值