2021——\(icpc\)(济南)
签到签慢了,签完都五百名,本来已经绝望准备下一长南京了。但还好C是博弈+组合数学。冲了出来,交的时候手都在抖。A了都没反应过来。喜得铜牌。
补题链接
K、Search For Mafuyu
给定一棵 n 个点的树,A 在 1 号点,B 的位置在 2-n 中均匀随机,A 不知道 B 的位置。现在 A 要去找 B,每秒可以走到一个相邻点,求在最优策略下的期望时间。
题解:刚开始一直没太懂最优策略是什么意思,瞎蒙了几个想法,一直不对。然后灵机一动,发现这个问题等价与遍历整棵树然后记录每个点到达的时间。求和之后乘上概率即可。现在就是解决怎样走会使这个求和最小,当时想的是贪心的走最近的,zzh直接就上机了,可能有点急躁,写了好一会没写出来。后来我上,写没写出来,这时候twh和我说多验证几个样例,发现只要是欧拉序就行(不会证明)。之后顺利上手1A。
/*PTA似乎看不到赛时自己提交的代码
*但自己又不想再写了*/
(^_^)
C、Optimal Strategy
有 n 件物品,第 i 件的价值为 a[i]。A 和 B 轮流取物品,A 先手。每个玩家都要最大化自己取到的物品的价值和,求有多少种可能的游戏过程。
题解:
签完到之后队友看D,我看C。我感觉C可以试一下。
这个题目思考过程大概是这样:
可以把拿起过程看作一个排列,比如说第一个样例:
2 2 1,1 2 2,因为不是同样的2所以,乘个全排列2!,就是4种。
现在只需要思考限制就行。
第二个样例每一种数都是偶数个,这其实已经是提示了。
在偶数情况下,只要有一个人选了当前最大的数,那么后面那个人就一定要跟着选一个一样大的 。不然一定会亏。
比如说:1 1 2 2 3 3,如果先手选了3,后手一定会选3。
所以在排列中最大的一定是成对在一起的。
当我们把排列中最大的数删掉之后第二大的就一定会成对,删掉第二大的之后第三大的就一定会成对.......
所以不妨从最小的开始考虑,先把最小的放好,再把第二小的成对插进去,这就是挡板法了,不难发现这一步等价于球不同,盒子不同,有空盒的球盒模型。依次推到下去我们可以得到数字全部都是偶数的推导公式(具体是啥我搞忘了)。
根据第三个样例就可以发现,存在奇数个的规则。
1 1 1 1 1 4 4 5 8 9 9 10
存在单独的数字时我们发现这是一个可以偷鸡的好机会,我拿了之后我必然比你多一个。这样可以得出结论当存在优先拿走最大单个数。
放在排列中,单个的10必然是第一个因为 它比所有的数字都大,而同样的单个的8一定会在1和4前面。
而且可以发现必然是先手拿10,后手拿8(虽然对这题没用但似乎可以出新题),因为其中一定有偶数个数字。
这体现了一个什么问题?单个对排列个数没卵用,因为我们是把大的往小的插空,单个的放在最前面就好了(但是记得乘排列的时候要乘)。
综上,可以得出整个问题的流程。
我知道有些人是从大到小处理排列的,因为开始我也是。但是这样你会发现单个数字是非常棘手的。
题解写的有点啰嗦了,而且没有代码,见谅见谅
后来补的:
J、Determinant
给定一个矩阵,并且给出它的精确行列式的绝对值
判断行列式的正负
题解:
这个题就是高斯消元求行列式。但是处理非常巧妙。其实高斯消元没咋学,就会一个板子,比赛的时候这个题就没想了。
这个要点是这样的:
一个数和他的相反数对一个奇数取模一定不同。
所以用高斯消元+取模的方式求一个行列式,再使用大数取模的方式对给定的精确行列式的绝对值取一个模。看他们是不是一样的就行。
因为不是自己想出来的所以就没那么多废话了
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll long long
const ll N = 105;
const ll mod = 1e9+7;
ll a[N][N];
ll fpow(ll b,ll n){
ll res = 1;
while(n){
if(n&1) res = 1ll*res*b%mod;
b = 1ll*b*b%mod;
n>>=1;
}
return res%mod;
}
ll Gauss(ll n){
ll det = 1;
for (ll i = 1; i <= n; ++i) {
ll k = i;
for (ll j = i + 1; j <= n; ++j)
if (abs(a[j][i]) > abs(a[k][i])) k = j;
if (abs(a[k][i]) == 0) {
det = 0;
break;
}
swap(a[i], a[k]);
if (i != k) det = -det;
det = (1ll*det*a[i][i]%mod+mod)%mod;
for (ll j = i + 1; j <= n; ++j) a[i][j] = 1ll*a[i][j]*fpow(a[i][i],mod-2)%mod;
for (ll j = 1; j <= n; ++j) {
if (j != i && a[j][i]) {
for (ll l = i + 1; l <= n; ++l) {
a[j][l] = (a[j][l] - 1ll*a[i][l] * a[j][i] % mod+mod) % mod;
}
}
}
}
return det;
}
char str[10005];
ll MOD(){
ll ans = str[0]-'0',len = strlen(str);
for(ll i = 1;i < len;i++){
ans = (ans*10%mod+str[i]-'0')%mod;
}
return ans;
}
int main() {
ll t;cin>>t;
while (t--) {
ll n;cin>>n;
cin>>str;
for (ll i = 1; i <= n; i++) {
for (ll j = 1; j <= n; j++) {
cin>>a[i][j];
}
}
ll det = Gauss(n);
// cout<<det<<' '<<MOD()<<endl;
puts(det==MOD()?"+":"-");
}
return 0;
}