1001. The Fool
整除分块,签到
#include
#define ll long long
using namespace std;
const int maxn = 2e5 + 10, mod = 1e9 + 7;
int main() {
int T, n, kase = 0;
cin>>T;
while (T--) {
cin>>n;
ll ans = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += 1ll * (r - l + 1) * (n / l);
}
printf("Case %d: ", ++kase);
if (ans % 2)
puts("odd");
else
puts("even");
}
}
1002. The World
签到
#include
#define ll long long
using namespace std;
const int maxn = 2e5 + 10;
string s, a, b, tp;
map<string, int> mp;
int gao(string tmp) {
if (tmp.length() == 5)
return (tmp[0] - '0') * 10 + tmp[1] - '0';
return tmp[0] - '0';
}
int main() {
int T, n, kase = 0;
mp["Beijing"] = 8;
mp["Washington"] = -5;
mp["London"] = 0;
mp["Moscow"] = 3;
cin>>T;
while (T--) {
cin>>s>>tp>>a>>b;
string res = "Today";
int time = gao(s);
if (time == 12)
time = 0;
if (tp == "PM")
time += 12;
time += mp[b] - mp[a];
if (time < 0) {
res = "Yesterday";
time += 24;
if (time >= 12) {
tp = "PM";
time -= 12;
}
else {
tp = "AM";
}
}
else if (time >= 24) {
res = "Tomorrow";
time -= 24;
if (time < 12)
tp = "AM";
else
tp = "PM";
}
else {
if (time >= 12)
tp = "PM", time -= 12;
else
tp = "AM";
}
if (!time)
time = 12;
string s2 = "";
if (time >= 10)
s2 += (time / 10 + '0');
s2 += (time % 10 + '0');
int pos = 2;
if (s.length() == 4)
pos--;
for (pos; pos < s.length(); pos++)
s2 += s[pos];
printf("Case %d: ", ++kase);
cout<<res<<" "<<s2<<" "<<tp<<endl;
}
}
1003. Justice
解法:首先,对于大于等于100000的ki值,我们不需要管,如果这些数总和大于等于1,那么肯定有解,我们先判断这些数总和是否大于等于1,我们用数组vis统计每个数出现次数,然后从大到小枚举x,vis[x] += vis[x + 1] / 2,如果到了最后vis[0]不为0,那么满足条件,第二步我们来组合,我们取出所有值小于等于20的ki,把他们全部变成2^(20 - ki),然后从到达小枚举这些数,直到这些数相加等于2^(19)为止,然后把这些数标记为1,其他全部标为0即可。
#include
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn], p[21], vis[maxn], vis2[maxn], ans[maxn];
struct node {
int v, id;
bool operator<(const node &t) const {
return v < t.v;
}
} b[maxn];
int main() {
int T, kase = 0;
scanf("%d", &T);
p[0] = 1;
for (int i = 1; i <= 20; i++)
p[i] = p[i - 1] * 2;
while (T--) {
int n, mx = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
ans[i] = 0;
if (a[i] >= 100000)
a[i] = 0;
vis[a[i]]++;
mx = max(mx, a[i]);
b[i] = node{a[i], i};
}
vis[0] = 0;
for (int i = 100000; i; i--)
if (vis[i])
vis[i - 1] += vis[i] / 2;
printf("Case %d: ", ++kase);
if (!vis[0]) {
for (int i = 1; i <= mx; i++)
vis[i] = 0;
puts("NO");
continue;
}
puts("YES");
ll res = 0;
sort(b + 1, b + 1 + n);
for (int i = 1; i <= n; i++)
if (b[i].v <= 20) {
int tmp = p[20 - b[i].v];
if (res + tmp <= p[19])
ans[b[i].id] = 1, res += tmp;
}
for (int i = 1; i <= n; i++)
if (a[i] >= 20)
printf("0");
else
printf("%d", ans[i]);
puts("");
for (int i = 1; i <= mx; i++)
vis[i] = 0;
}
}
1004. The Moon
解法:设d[i][j]为 q 增加了 i 次 2%,j 次 1.5%,也就是 q = 0.02 + 0.02 * i + 0.015 * j,且仍然失败的概率,我们可以下一次就操作成功,那么ans += d[i][j] * p * q * (i + j + 1),下一次有可能直接打怪没打赢,d[i][j + 1] += d[i][j] * (1 - p),下一次也可能打赢怪但是没抽中奖,d[i + 1][j] += d[i][j] * p * (1 - q),如果当前的 q > 1,那么不用接续转移了,直接算贡献,ans += d[i][j] * (i + j) + d[i][j] / p。
#include
#define db double
#define ll long long
using namespace std;
db d[52][70];
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
int x;
cin>>x;
db p = 0.01 * x, ans = 0.0;
for (int i = 0; i <= 50; i++)
for (int j = 0; j <= 70; j++)
d[i][j] = 0.0;
d[0][0] = 1.0;
for (int i = 0; i <= 49; i++) {
for (int j = 0; j <= 70; j++) {
db p1 = 0.02 + 0.02 * i + 0.015 * j;
if (p1 > 1.0) {
ans += d[i][j] * (i + j) + d[i][j] / p;
break;
}
ans += d[i][j] * (i + j + 1) * p * p1;
d[i + 1][j] += d[i][j] * p * (1.0 - p1);
d[i][j + 1] += d[i][j] * (1.0 - p);
}
}
printf("Case %d: %.10f\n", ++kase, ans);
}
}
1006. The Hermit
题意:对于每个点 i, 它能覆盖范围是 [i - ri + 1, i + ri - 1],且对于任意相邻点i,i + 1,i + 1 的覆盖的左边界一定大于等于 i 覆盖的左边界,对于每个点 i,它的权值定义为合法k的数量,定义k合法:k < i,且 k 在 i 的覆盖范围内,且存在一个点 j,k < j < i,且 dist(k, j) >= dist(j, i),且 i 和 k 都在 j 的覆盖范围内。要求每个点的权值异或和
解法:题意很绕,题目贼水,对于 ri < 3 的点,显然权值为0,对于 ri >= 3 的点,我们由题意得,ri - 1 覆盖的左边界一定 <= ri 覆盖的左边界,也就是说我设置 j = i - 1,其他 i 左边能覆盖的点都可以作为合法的 k 点,也就是说, i 的权值为 ri - 2。
#include
#define ll long long
using namespace std;
const int maxn = 1e6 + 10, N = 1e6;
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
int n, x, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
if (x >= 3)
ans ^= (x - 2);
}
printf("Case %d: %d\n", ++kase, ans);
}
}
1008. Lovers
解法:我们把每次操作分开处理,用tagR[o]标记往右边加的数字,R[o]为该区间右边加数字后的总和,len[o] 为该区间加了多少次,我们来下传一下标记,对于 fa 节点的信息要下传到 o 节点(假设 o 节点长度为n),首先R[o] *= 10^len[fa],然后R[o] += ragR[fa] * n,然后tagR[o] = tagR[o] * 10^len[fa],ok,右边加数很简单,现在来用tagL[o] 和 L[o] 来搞定左边加数,tagL[o]表示的数字是tagR[o]顺序是反着的,L[o]为该区间所有数字左边的一半乘以10^len/2的总和,设sum[o] 为区间 " 总和 ",初始值sum[o]为区间长度,每次更新了一次区间,那么该区间的sum[o] *= 100,下传标记:L[o] = L[o] * 10 ^len[fa] (因为右边加了这么多数) + tagL[fa] * sum[o] * 10^len[fa],tagL[o] = tagL[o] + tagL[fa] * 10^len[o]),最后更新len[o] += len[fa],sum[o] *= 10^(len[fa] * 2)
#include
#define ll long long
using namespace std;
const int maxn = 2e5 + 10, mod = 1e9 + 7;
ll sum[maxn * 4], L[maxn * 4], R[maxn * 4], tagL[maxn * 4], tagR[maxn * 4], p[maxn];
int len[maxn * 4];
char s[20];
#define ls o * 2
#define rs o * 2 + 1
void gao(int o, int fa, int n) {
R[o] = (R[o] * p[len[fa]] + tagR[fa] * n) % mod;
tagR[o] = (tagR[o] * p[len[fa]] + tagR[fa]) % mod;
len[o] += len[fa];
L[o] = (L[o] * p[len[fa]] % mod + tagL[fa] * sum[o] % mod * p[len[fa]] % mod) % mod;
tagL[o] = (tagL[o] + tagL[fa] * p[len[o] - len[fa]]) % mod;
sum[o] = sum[o] * p[len[fa] * 2] % mod;
}
void pushdown(int o, int l, int m, int r) {
if (len[o]) {
gao(ls, o, m - l + 1);
gao(rs, o, r - m);
tagL[o] = tagR[o] = len[o] = 0;
}
}
void pushup(int o) {
L[o] = (L[ls] + L[rs]) % mod;
R[o] = (R[ls] + R[rs]) % mod;
sum[o] = (sum[ls] + sum[rs]) % mod;
}
void build(int o, int l, int r) {
L[o] = R[o] = tagL[o] = tagR[o] = len[o] = 0;
if (l == r) {
sum[o] = 1;
return;
}
int m = (l + r) / 2;
build(ls, l, m);
build(rs, m + 1, r);
pushup(o);
}
void up(int o, int l, int r, int ql, int qr, int x) {
if (l >= ql && r <= qr) {
tagR[o] = (tagR[o] * 10 + x) % mod;
len[o]++;
R[o] = (R[o] * 10 + 1ll * x * (r - l + 1)) % mod;
L[o] = (L[o] * 10 + sum[o] * x * 10) % mod;
tagL[o] = (tagL[o] + p[len[o] - 1] * x) % mod;
sum[o] = sum[o] * 100 % mod;
return;
}
int m = (l + r) / 2;
pushdown(o, l, m, r);
if (ql <= m)
up(ls, l, m, ql, qr, x);
if (qr > m)
up(rs, m + 1, r, ql, qr, x);
pushup(o);
}
ll qu(int o, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr)
return (L[o] + R[o]) % mod;
int m = (l + r) / 2;
pushdown(o, l, m, r);
ll res = 0;
if (ql <= m)
res += qu(ls, l, m, ql, qr);
if (qr > m)
res += qu(rs, m + 1, r, ql, qr);
return res % mod;
}
int main() {
int T, kase = 0;
scanf("%d", &T);
p[0] = 1;
for (int i = 1; i <= 200000; i++)
p[i] = p[i - 1] * 10 % mod;
while (T--) {
int n, m, l, r, x;
printf("Case %d:\n", ++kase);
scanf("%d%d", &n, &m);
build(1, 1, n);
while (m--) {
scanf("%s%d%d", s, &l, &r);
if (s[0] == 'w') {
scanf("%d", &x);
up(1, 1, n, l, r, x);
}
else
printf("%lld\n", qu(1, 1, n, l, r));
}
}
}
1009. Strength
题意:你有 m 个卡片要么处于攻击状态要么处于防御状态,我有 n 个卡片,每个卡片只能用一次,我如果选择一张卡片攻击你的攻击状态卡片,如果我的卡片攻击力>=你的卡片攻击力,那么你的那张被攻击的卡片就会作废,并且你会损失攻击力之差的血量,如果我选择一张卡片攻击你防御状态的卡片,如果我的卡片攻击力>=你的卡片攻击力,那么你的卡片作废,但是你不会损失血量,如果你没有卡片剩余,你损失的血量将是我剩余的卡片的攻击力总和。求你最大损失的血量。
解法:我们只要两个策略,第一个:我的所有卡片进攻你的攻击状态卡片,第二种:我先全部进攻你的防御状态卡片,如果我还有卡片剩余,那么再全部进攻你的攻击状态卡片,如果还有剩余,就全部进攻你。进攻防御状态的卡片的贪心策略过于简单,我们讲讲怎么进攻攻击状态的卡片,我门首先二分或者双指针求一下我最多能打赢对方几个卡片,然后我和对方的卡片对排序,假设我最多能打赢 k 个卡片,我门从 1 开始枚举 i,我最大的 i 张卡片的和 - 对方最小的 i 张卡片的和就是对方扣的血量,我么取一个最大值即可。
#include
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn], b[maxn], c[maxn], d[maxn], vis[maxn], n1, n2, n3;
ll sum1[maxn], sum2[maxn];
int ok(int k) {
int p = n1 - k;
for (int i = 1; i <= k; i++)
if (a[i + p] < b[i])
return 0;
return 1;
}
ll gao(int tp) {
if (!n2) {
if (!tp)
return 0;
return sum1[n1];
}
if (a[n1] <= b[1])
return 0;
int l = 1, r = min(n1, n2);
while (l < r) {
int m = (l + r) / 2;
if (ok(m))
l = m + 1;
else
r = m;
}
if (!ok(l))
l--;
ll ans = 0;
if (tp && l == n2)
ans = sum1[n1] - sum2[n2];
for (int i = 1; i <= l; i++)
ans = max(ans, sum1[n1] - sum1[n1 - i] - sum2[i]);
return ans;
}
int gao2() {
if (!n3 || n1 == n3)
return 1;
int p = 1, q = 1;
while (p <= n1 && q <= n3)
if (a[p] >= c[q]) {
vis[p] = 1;
p++, q++;
}
else
p++;
if (q <= n3)
return 0;
int tmp = n1;
n1 = 0;
for (int i = 1; i <= tmp; i++)
if (!vis[i])
a[++n1] = a[i], sum1[n1] = sum1[n1 - 1] + a[n1];
return 1;
}
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
int n, m, x;
scanf("%d%d", &n, &m);
n1 = n2 = n3 = 0;
for (int i = 1; i <= n; i++)
scanf("%d", &a[++n1]), vis[i] = 0;
for (int i = 1; i <= m; i++)
scanf("%d", &d[i]);
for (int i = 1; i <= m; i++) {
scanf("%d", &x);
if (x)
c[++n3] = d[i];
else
b[++n2] = d[i];
}
sort(a + 1, a + 1 + n1);
sort(b + 1, b + 1 + n2);
sort(c + 1, c + 1 + n3);
for (int i = 1; i <= n1; i++)
sum1[i] = sum1[i - 1] + a[i];
for (int i = 1; i <= n2; i++)
sum2[i] = sum2[i - 1] + b[i];
ll ans = gao(0);
if (gao2())
ans = max(ans, gao(1));
printf("Case %d: %lld\n", ++kase, ans);
}
}