I.Characters with Hash
签到题。消掉前缀零,特判一下差小于10的情况和全0的情况即可。
ac代码:
#include
using namespace std;
char p, s[1000005];
int main() {
int t, n;
scanf("%d", &t);
while(t--) {
scanf("%d\n%c%s", &n, &p, s);
int i = 0, len = strlen(s), ans;
while(i < len && p - s[i] == 0) {
i++;
}
ans = (len - i) * 2;
if(p - s[i] < 10){
ans -= 1;
}
if(ans <= 0) {
ans = 1;
}
printf("%d\n", ans);
}
return 0;
}
B. BE, GE or NE
博弈题。
但是这题比较强,传统的博弈题只分胜负,最多加个平手,而这题随着最后游戏分数的区间不同,划分三种结局!!!
从传统的角度把这题抽象一下,就是好像有一根指针,在区间上移动,最后停下的位置代表着结局。如果逆向思维一下,把这跟指针看成相对静止,变成区间在移动的话……
三种操作,加,减,乘-1随着当前玩家的不同,就变成了另外一种东西。
对于希望得到GE的玩家:
加:GE区间扩大,BE区间缩小直至消失,消失后压缩NE区间
减:与加相反,BE区间扩大。
乘-1:区间翻转。
对于希望得到BE的玩家:
呃,跟楼上相反,乘-1还是区间翻转。
然后我们分别考虑这三种走法对区间的影响,最后取个并,就是当前的最理想结局。
用字符串模拟,最后判一下s[m]是什么状态,即可得到结果。
%%权哥!
ac代码:
#include
using namespace std;
const int maxn = 1005;
struct Query {
int a, b, c;
} q[maxn];
int main() {
// k,GE;l,BE
int n, m, k, l;
char a[205], b[205], c[205], s[205];
scanf("%d%d%d%d", &n, &m, &k, &l);
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &q[i].a, &q[i].b, &q[i].c);
}
m += 100;
k += 100;
l += 100;
for(int i = 0; i <= l; i++) {
s[i] = 'B';
}
for(int i = l + 1; i < k; i++) {
s[i] = 'N';
}
for(int i = k; i <= 200; i++) {
s[i] = 'G';
}
for(int num = n; num > 0; num--) {
if(q[num].a > 0) {
for(int i = 0; i <= 200; i++) {
a[i] = s[200];
}
for(int i = 0; i <= 200 - q[num].a; i++) {
a[i] = s[i + q[num].a];
}
}
if(q[num].b > 0) {
for(int i = 0; i <= 200; i++) {
b[i] = s[0];
}
for(int i = q[num].b; i <= 200; i++) {
b[i] = s[i - q[num].b];
}
}
if(q[num].c > 0) {
for(int i = 0; i <= 200; i++) {
c[i] = s[200 - i];
}
}
// 判断当前是谁在走
if(num & 1) {
for(int i = 0; i <= 200; i++) {
s[i] = 'B';
if((q[num].a && a[i] == 'G') || (q[num].b && b[i] == 'G') || (q[num].c && c[i] == 'G')) {
s[i] = 'G';
continue;
}
if((q[num].a && a[i] == 'N') || (q[num].b && b[i] == 'N') || (q[num].c && c[i] == 'N')) {
s[i] = 'N';
}
}
} else {
for(int i = 0; i <= 200; i++) {
s[i] = 'G';
if((q[num].a && a[i] == 'B') || (q[num].b && b[i] == 'B') || (q[num].c && c[i] == 'B')) {
s[i] = 'B';
continue;
}
if((q[num].a && a[i] == 'N') || (q[num].b && b[i] == 'N') || (q[num].c && c[i] == 'N')) {
s[i] = 'N';
}
}
}
}
if(s[m] == 'G') {
printf("Good Ending\n");
} else if(s[m] == 'B') {
printf("Bad Ending\n");
} else {
printf("Normal Ending\n");
}
return 0;
}
H.Ryuji doesn’t want to study
主要就是搞那个式子,我不会化简,我看网上有人化到最后得出“这不就是俩前缀和嘛”的结论。
怎么说,线段树维护区间和和权值和就好了。
ac代码:
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
struct Ans {
ll sum, val;
};
int n, q;
ll in[maxn], sum[maxn << 2], val[maxn << 2];
void pushUp(int i) {
sum[i] = sum[i << 1] + sum[i << 1 | 1];
val[i] = val[i << 1] + val[i << 1 | 1];
}
void build(int i, int l, int r) {
if(l == r) {
sum[i] = in[l];
val[i] = in[l] * (n - l + 1);
return;
}
int mid = (l + r) / 2;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
pushUp(i);
}
void update(int i, int l, int r, int pos, ll v) {
if(l == r) {
sum[i] = v;
val[i] = v * (n - pos + 1);
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) {
update(i << 1, l, mid, pos, v);
} else {
update(i << 1 | 1, mid + 1, r, pos, v);
}
pushUp(i);
}
Ans query(int i, int l, int r, int L, int R) {
if(l >= L && r <= R) {
return {sum[i], val[i]};
}
int mid = (l + r) >> 1;
Ans left = {0, 0}, right = {0, 0};
if(L <= mid) {
left = query(i << 1, l, mid, L, R);
}
if(R > mid) {
right = query(i << 1 | 1, mid + 1, r, L, R);
}
return {left.sum + right.sum, left.val + right.val};
}
int main() {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i++) {
scanf("%d", &in[i]);
}
build(1, 1, n);
int a, b, c;
while(q--) {
scanf("%d%d%d", &a, &b, &c);
if(a == 1) {
Ans ans = query(1, 1, n, b, c);
printf("%lld\n", ans.val - ans.sum * (n - c));
} else {
update(1, 1, n, b, c);
}
}
return 0;
}