题解
A. Sagheer and Crossroads
额。题意杀。
半天没搞懂这题要干啥!代码好丑。
#include <iostream>
#include <cstdio>
using namespace std;
int m[5][5];
int main()
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
cin >> m[i][j];
int ok = 1;
if(m[1][4]) {
if(m[1][1]||m[1][2]||m[1][3]||m[2][1]||m[4][3]||m[3][2]) ok = 0;
}
if(m[2][4]) {
if(m[2][1]||m[2][2]||m[2][3]||m[3][1]||m[4][2]||m[1][3]) ok = 0;
}
if(m[3][4]) {
if(m[3][1]||m[3][2]||m[3][3]||m[4][1]||m[1][2]||m[2][3]) ok = 0;
}
if(m[4][4]) {
if(m[4][1]||m[4][2]||m[4][3]||m[1][1]||m[2][2]||m[3][3]) ok = 0;
}
printf("%s
", (ok==0)?"YES":"NO");
}
B. Sagheer, the Hausmeister
又是题意杀。英语真是辣鸡。【不过比一个叫做“黄焖蓉”的队友还是好那么一点】
施展一下DP这题还是不太难的。
dp[i][0]: 把前i楼全部搞定,且位于第i楼左端 の 最小耗费
dp[i][1]: 把前i楼全部搞定,且位于第i楼右端 の 最小耗费
转移方式有四种:
左左,右右,左右,右左。
然后是一堆特判:
- 比较高的楼层一片黑暗,所以无需“独上危楼听风雨,举杯邀影念旧情”啦!
- 某一个楼层灯全是灭的,这种楼层吓死人了。所以状态转移时姿势要变一下。
代码还是写得这么辣鸡。我也很绝望
#include <iostream>
#include <cstring>
using namespace std;
int n, m, dp[102][2];
char s[102][102];
int main()
{
cin >> n >> m;
for(int i=n;i>=1;i--) {
scanf("%s", s[i]+1);
}
dp[0][0] = -1, dp[0][1] = 100000000;
while(1) {
int ac = 0;
for(int i=2;i<=m+1;i++) {
if(s[n][i] == '1') {
ac = 1;
}
}
if(ac == 0) n--;
if(ac) break;
if(n==0) break;
}
if(n == 0) {
cout << 0 << endl;
return 0;
}
for(int i=1;i<n;i++) {
int p1 = -1, p2 = -1;
for(int j=2;j<=m+1;j++) {
if(s[i][j] == '1') {
p1 = j; break;
}
}
for(int j=m+1;j>=2;j--) {
if(s[i][j] == '1') {
p2 = j; break;
}
}
if(p1 == -1) {
dp[i][0] = min(dp[i-1][0]+1, dp[i-1][1]+m+2);
dp[i][1] = min(dp[i-1][1]+1, dp[i-1][0]+m+2);
continue;
}
dp[i][0] = min(dp[i-1][1] + m+2, dp[i-1][0] + 1 + 2*(p2-1));
dp[i][1] = min(dp[i-1][0] + m+2, dp[i-1][1] + 1 + 2*(m+2-p1));
}
int ans = 1000000000;
for(int i=2;i<=m+1;i++) {
if(s[n][i] == '1') {
ans = min(ans, dp[n-1][1]+m+3-i);
break;
}
}
for(int i=m+1;i>=2;i--) {
if(s[n][i] == '1') {
ans = min(ans, dp[n-1][0]+i);
break;
}
}
printf("%d
", ans);
}
C. Sagheer and Nubian Market
C比B还是简单那么一点点。
二分要拿多少个物品。每一次check都捡最便宜的物品。就行了。
code:
我觉得自己还是别写代码了比较好。:(´°ω°`」 ∠):
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
LL it[100000+10], a[100000+10];
LL n, S, T;
bool chk(int mid) {
for(int i=1;i<=n;i++) {
a[i] = it[i] + (LL)mid * i;
}
sort(a+1, a+1+n);
LL sum = 0;
for(int i=1;i<=mid;i++) {
sum += a[i];
}
bool ok_ = (sum <= S);
if(ok_) T = sum;
return ok_;
}
int main()
{
cin >> n >> S;
for(int i=1;i<=n;i++) {
scanf("%lld", &it[i]);
}
int L = 0, R = n;
while(R - L > 1) {
int mid = (L+R)/2;
if(chk(mid)) {
L = mid;
} else {
R = mid;
}
}
if(chk(R)) L = R;
chk(L);
cout << L << " " << T << endl;
}
E. Sagheer and Apple Tree
我们先将这棵树各节点红蓝交替染色。如果叶子节点为红色的。那么蓝色节点上的苹果对最终胜负就没有影响了。(因为蓝色节点上的苹果只能移动到红色节点,然后下一个人可以把这些苹果又移到蓝色节点上)【这玩意就是传说中的阶梯博弈模型】
1)若红色节点上的nim和为0.
那么执行完交换操作后,仍要保持住红色节点nim和为0的状态所以可以
- 交换两个蓝色节点
- 交换两个红色节点
- 将两个数目相等是红蓝节点交换
2)若红色节点上的nim和不为0.
那我们得抢救一番,使得红色节点nim和为0.拿map施展一下即可。
#include <iostream>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const int NICO = 100000+10;
int n, dep[NICO], a[NICO], p[NICO];
vector<int> v[NICO], v1, v2;
map<int, int> mp;
void dfs(int x) {
for(int i=0;i<v[x].size();i++) {
dep[v[x][i]] = dep[x] + 1;
dfs(v[x][i]);
}
}
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
for(int i=2;i<=n;i++) {
scanf("%d", &p[i]);
v[p[i]].push_back(i);
}
dep[1]=1; dfs(1);
int mx = -1;
for(int i=1;i<=n;i++) {
mx = max(mx, dep[i]);
}
int nim = 0;
for(int i=1;i<=n;i++) {
if(dep[i]%2 == mx%2) {
v1.push_back(a[i]);
nim ^= a[i];
} else {
v2.push_back(a[i]);
mp[a[i]] ++;
}
}
LL ans = 0;
if(nim == 0) {
ans += (LL)v1.size()*((LL)v1.size() - 1)/2;
ans += (LL)v2.size()*((LL)v2.size() - 1)/2;
}
for(int i=0;i<v1.size();i++) {
ans += mp[nim^v1[i]];
}
cout << ans << endl;
}
比赛过程
11 min A题 1Y 被自己惊人英语水平震撼。完全靠看样例解释和瞎猜过日子。
30 min C题 1Y 二分一直死循环。边界杀。
65 min B题 1Y 被自己惊人的码力震撼。dp写得太迷了。
然后在flash造反,网速爆炸的环境下hack了几发A.
然后是E题。排骨龙选手,比赛后半段一直处于啥都不想干的咸鱼模式。到了105分钟的时候终于终于终于开始读E题了,先是读错题,读对后,啥也没想出。其实E很水的呀!(° ꈊ °)✧˖°オホッ! 比赛排骨龙一直处于脑子生锈状态。哦,不对,是没脑子状态(бвб)。。最近排骨龙选手,经历了鼠粮不见了+饮水机不见了+快递半天不到这一系列大快人心的事情。所以比较躁动。(( ≧ꀦ≦))
1.%qls E题的全场FB。
2.%宇宙智障 E题居然得到施展了+代码全场最短。【宇宙智障都能A的题,一定是水题吧!
(◍ ૢ´꒳`◍ ૢ)】