A.Social Distancing
题意:
给定和
,要找
个整点,使得他们两两距离的平方和最大,并且所有点到原点的距离必须小于
题解:
cf460E。网上找了一份能过的代码(还有一份暴力枚举的只能过66.6%)戳我~
然后打个表就行
打表代码
#include <stdio.h>
#include <math.h>
#include <vector>
using namespace std;
struct point
{
int x, y;
point(int a = 0, int b = 0)
{
x = a;
y = b;
}
} t;
point operator-(point a, point b)
{
return point(a.x - b.x, a.y - b.y);
}
int operator*(point a, point b)
{
return a.x * b.y - a.y * b.x;
}
vector<point> p;
vector<int> now, bes;
int n, r, ans;
void dfs(int chos, int las, int sx, int sy, int sx2, int sy2)
{
if (chos == n)
{
if (ans < n * (sx2 + sy2) - sx * sx - sy * sy)
{
ans = n * (sx2 + sy2) - sx * sx - sy * sy;
bes = now;
}
return;
}
for (int i = las; i < p.size(); i++)
{
now.push_back(i);
dfs(chos + 1, i, sx + p[i].x, sy + p[i].y, sx2 + p[i].x * p[i].x, sy2 + p[i].y * p[i].y);
now.pop_back();
}
}
int main()
{
freopen("out.txt", "w", stdout);
for (int l = 1; l <= 8; l++)
for (int k = 1; k <= 30; k++)
{
n = l,r = k;
p.clear();
now.clear();
bes.clear();
int i, s;
for (i = -r; i <= 0; i++)
{
p.push_back(point(i, (int)sqrt(r * r - i * i)));
while (p.size() > 2 && (p[p.size() - 2] - p[p.size() - 3]) * (p[p.size() - 1] - p[p.size() - 2]) >= 0)
{
p[p.size() - 2] = p[p.size() - 1];
p.pop_back();
}
}
s = p.size();
for (i = s - 2; i >= 0; i--)
p.push_back(point(-p[i].x, p[i].y));
for (i = 1; i < s; i++)
p.push_back(point(-p[i].x, -p[i].y));
for (i = s - 2; i > 0; i--)
p.push_back(point(p[i].x, -p[i].y));
ans = 0;
dfs(0, 0, 0, 0, 0, 0);
printf("%d,", ans);
}
return 0;
} AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int ans[8][30]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,36,64,100,144,196,256,324,400,484,576,676,784,900,1024,1156,1296,1444,1600,1764,1936,2116,2304,2500,2704,2916,3136,3364,3600,8,32,76,130,224,312,416,554,722,896,1064,1248,1512,1746,2016,2264,2600,2888,3218,3584,3912,4344,4712,5138,5612,6062,6536,6984,7520,8084,16,64,144,256,400,576,784,1024,1296,1600,1936,2304,2704,3136,3600,4096,4624,5184,5776,6400,7056,7744,8464,9216,10000,10816,11664,12544,13456,14400,24,96,218,384,624,880,1188,1572,2014,2496,2984,3520,4224,4870,5616,6336,7224,8056,9008,9984,10942,12080,13144,14326,15624,16896,18184,19488,20968,22480,36,144,324,576,900,1296,1764,2304,2916,3600,4356,5184,6084,7056,8100,9216,10404,11664,12996,14400,15876,17424,19044,20736,22500,24336,26244,28224,30276,32400,48,192,432,768,1224,1740,2356,3102,3954,4896,5872,6960,8280,9564,11016,12456,14160,15816,17666,19584,21500,23688,25808,28122,30624,33120,35664,38266,41200,44076,64,256,576,1024,1600,2304,3136,4096,5184,6400,7744,9216,10816,12544,14400,16384,18496,20736,23104,25600,28224,30976,33856,36864,40000,43264,46656,50176,53824,57600};
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,r;
scanf("%d%d",&n,&r);
printf("%d\n",ans[n-1][r-1]);
}
return 0;
} B.Mask Allocation
题意:
有个口罩,要求装最少的箱,使得在个数平均的情况下,既能分箱分给
个医院,也能分给
个医院。输出字典序最大输出方案
题解:
令,因为要凑出
个医院,因此每箱口罩最多为
个。
考虑个医院的情况,上限为
,为了使箱数最少,因此要尽可能多的装
个,每个医院要
箱,因此可以封装
个
的口罩,还需要
个口罩。
再考虑个医院,已经分配了
箱
的口罩,因此还有
的医院需要
的口罩。
结合上面两种医院,问题就从变为了
,推到就觉得很熟悉,这就是
,那照着求
的写法写即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 210;
vector<int> ans;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
ans.clear();
int n, m;
scanf("%d%d", &n, &m);
int a = min(n, m);
int b = max(n, m);
while (a)
{
for (int i = 1; i <= b - b % a; i++)
ans.push_back(a);
int t = b % a;
b = a;
a = t;
}
printf("%d\n", ans.size());
for (auto i : ans)
printf("%d ", i);
puts("");
}
return 0;
} C.A National Pandemic
题意:
现在有一棵大小为的树,有
个操作,每次有三种操作:
定义为从
到
的边数
1 位置
上的权值
,同时所有位置的权值加上
2. 将
位置的权值对
取个最小值
3. 问
位置的权值是多少
题解:
对于操作,只需要令根节点
的值
即可,那么其他点的权值就是
,因为每进行一次操作就要
,同时对于节点
还要减去
,每次的
已经用
统计了,因此可以用
记录操作
的次数,结果就是
。
但是发现带入根节点到节点路径上的点结果不对,结果不应该是
而是
,为了使操作统一,可以用树链剖分来维护链,当对
进行操作
时,让整条链上的值都加上
(
是因为原来
,然后这条链上的需要
,
),因此结果为
,其中
表示
与
路径上每个点的结果之和,但是刚才讨论的
其实是对路径上的每条边都
,这里用的
是对每个点,当然你实现的时候可以用边来表示,只需要把
中最后一次
换成
即可,这里就直接减去
了,最终答案为
对于操作,因为每次都只知道根节点的权值
,每个点的权值就是直接算的,可以为每个节点设置一个变量
,这时每个节点的权值就为
,每个算出这个结果与
进行比较,如果比
就将权值赋给
即可
对于操作就是上述的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
int head[maxn], dfn[maxn], dep[maxn], siz[maxn], top[maxn], son[maxn], fa[maxn];
int n, m, cnt, tot;
ll ad[maxn], T[maxn << 2], lazy[maxn << 2];
struct Edge
{
int v, next;
} E[maxn << 1];
void init()
{
memset(head, -1, sizeof(head));
memset(son, -1, sizeof(son));
memset(ad, 0, sizeof(ad));
memset(T, 0, sizeof(T));
memset(lazy, 0, sizeof(lazy));
cnt = tot = 0;
}
void addedge(int u, int v)
{
E[cnt].v = v;
E[cnt].next = head[u];
head[u] = cnt++;
}
void dfs1(int x, int f, int deep)
{
siz[x] = 1;
fa[x] = f;
dep[x] = deep;
for (int i = head[x]; ~i; i = E[i].next)
{
int v = E[i].v;
if (v == f)
continue;
dfs1(v, x, deep + 1);
siz[x] += siz[v];
if (son[x] == -1 || siz[son[x]] < siz[v])
son[x] = v;
}
}
void dfs2(int x, int tp)
{
dfn[x] = ++tot;
top[x] = tp;
if (son[x] != -1)
dfs2(son[x], tp);
for (int i = head[x]; ~i; i = E[i].next)
{
int v = E[i].v;
if (v == fa[x] || v == son[x])
continue;
dfs2(v, v);
}
}
ll pushup(int rt)
{
T[rt] = T[rt << 1] + T[rt << 1 | 1];
}
void pushdown(int rt, int l, int r)
{
if (lazy[rt])
{
int mid = l + r >> 1;
T[rt << 1] += (mid - l + 1) * lazy[rt];
T[rt << 1 | 1] += (r - mid) * lazy[rt];
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
void update(int l, int r, int L, int R, int rt, ll val)
{
if (L <= l && r <= R)
{
T[rt] += (r - l + 1) * val;
lazy[rt] += val;
return;
}
pushdown(rt, l, r);
int mid = l + r >> 1;
if (R <= mid)
update(l, mid, L, R, rt << 1, val);
else if (L > mid)
update(mid + 1, r, L, R, rt << 1 | 1, val);
else
{
update(l, mid, L, mid, rt << 1, val);
update(mid + 1, r, mid + 1, R, rt << 1 | 1, val);
}
pushup(rt);
}
ll query(int l, int r, int L, int R, int rt)
{
if (L <= l && r <= R)
return T[rt];
pushdown(rt, l, r);
int mid = l + r >> 1;
if (R <= mid)
return query(l, mid, L, R, rt << 1);
else if (L > mid)
return query(mid + 1, r, L, R, rt << 1 | 1);
else
return query(l, mid, L, mid, rt << 1) + query(mid + 1, r, mid + 1, R, rt << 1 | 1);
}
void modify(int u, int v, ll val)
{
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
swap(u, v);
update(1, n, dfn[top[u]], dfn[u], 1, val);
u = fa[top[u]];
}
if (dep[u] < dep[v])
swap(u, v);
update(1, n, dfn[v], dfn[u], 1, val);
}
ll ask(int u, int v)
{
ll ans = 0;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
swap(u, v);
ans += query(1, n, dfn[top[u]], dfn[u], 1);
u = fa[top[u]];
}
if (dep[u] < dep[v])
swap(u, v);
ans += query(1, n, dfn[v], dfn[u], 1);
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
init();
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
dfs1(1, 0, 0);
dfs2(1, 1);
int num = 0;
ll val = 0;
while (m--)
{
int op, x, w;
scanf("%d%d", &op, &x);
if (op == 1)
{
scanf("%d", &w);
num++;
modify(1, x, 2);
val += w - dep[x];
}
else if (op == 2)
{
ll v = val + ask(1, x) - 1ll * dep[x] * num - query(1, n, 1, 1, 1);
if (v > ad[x])
ad[x] = v;
}
else
printf("%lld\n", val + ask(1, x) - 1ll * dep[x] * num - query(1, n, 1, 1, 1) - ad[x]);
}
}
return 0;
} D.Fake News
题意:
给定一个,判断
是否为一个平方数
题解:
从只有
和
,因此直接猜了猜就过了QAQ
具体证明
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
ll n;
scanf("%lld",&n);
if(n==1||n==24)
puts("Fake news!");
else
puts("Nobody knows it better than me!");
}
return 0;
} H.Dividing
题意:
正整数二元组 Legend Tuple (n, k) 是这样定义的
- (1, k) 总是 Legend Tuple
- 若 (n, k) 是 Legend Tuple, 那么 (n + k, k) 也是
- 若 (n, k) 是 Legend Tuple, 那么 (nk, k) 也是
统计有多少个 Legend Tuple (n, k) 满足 , 其中
和
是不超过
的整数
题解:
显然和
就为答案
因此答案为。裸的数论分块,考虑到
会重复,因此把
的贡献
单独给出,
从
开始即可
数论分块
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll f(ll n, ll k)
{
ll ans = 0;
for (ll l = 2, r = 0; l <= k; l = r + 1)
{
if (n / l == 0)
break;
r = n / (n / l);
r = min(r, k);
ans += (r - l + 1) % mod * (n / l) % mod;
ans = ans % mod;
}
return ans;
}
int main()
{
ll n, k;
scanf("%lld%lld", &n, &k);
ll ans = n + k - 1;
ans = (n + k - 1 + f(n, k) + f(n - 1, k)) % mod;
printf("%lld\n", ans);
return 0;
} J.Pointer Analysis
题意:
一个程序中有个对象, 每个对象有
个成员指针变量. 同时还有
个普通的指针变量. 给定
条赋值 语句, 询问在以任意顺序执行每条语句无限多次的过程中, 每个指针变量可能指向的对象集合.
题解:
第1、2种操作就是赋值。
对于第3、4种操作,比如 A = B.f ,B.f 说的是 B 指向的对象(所以要判断B是否为空)的成员变量 f ,而这个成员变量 f 指向了另一个对象,与 B 是无关的,搞个三维数组,然后进行赋值。A.f = B 反过来写就是了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, ans[30][30], a[30][30][30];
char s1[222][5], s2[222][5];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%s%s%s", s1[i] + 1, s2[i] + 1, s2[i] + 1);
int T = n;
while (T--)
{
for (int i = 1; i <= n; i++)
{
int l1 = strlen(s1[i] + 1);
int l2 = strlen(s2[i] + 1);
int c1 = s1[i][1] - 'A';
int c2 = s2[i][1] - 'A';
if (l1 == l2)
{
if (s2[i][1] >= 'a') //A = a
ans[c1][s2[i][1] - 'a'] = 1;
else // A = B
for (int j = 0; j < 26; j++)
ans[c1][j] |= ans[c2][j];
}
else if (l2 >= 3) // A = B.f
{
int c3 = s2[i][3] - 'a'; //c3是成员
for (int j = 0; j < 26; j++) //j是对象
if (ans[c2][j]) //k是第二层对象
for (int k = 0; k < 26; k++)
ans[c1][k] |= a[c3][j][k];
}
else // A.f = B
{
int c3 = s1[i][3] - 'a';
for (int j = 0; j < 26; j++)
if (ans[c1][j])
for (int k = 0; k < 26; k++)
a[c3][j][k] |= ans[c2][k];
}
}
}
for (int i = 0; i < 26; i++)
{
printf("%c: ", 'A' + i);
for (int j = 0; j < 26; j++)
if (ans[i][j])
printf("%c", 'a' + j);
puts("");
}
return 0;
} 
京公网安备 11010502036488号