A. Reorder
给定一串数列和m,问是否可能存在一个重排令
[sum_{i=1}^{n}sum_{j=i}^{n}(double)a_{j}/j==m ]
直接和是否等于m
#include<iostream>
#include<queue>
#include<map>
#include<utility>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<cmath>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
typedef pair<int, int> P;
ll m;
int main() {
cin >> m;
while (m--)
{
ll a, b;
cin >> a >> b;
ll ans = 0;
for (int i = 0; i < a; i++) {
ll tmp;
cin >> tmp;
ans += tmp;
}
if (ans == b)cout << "YES
";
else cout << "NO
";
}
}
B .Prime Square
给定n,求一个n×n的矩阵,令矩阵中每个数字都不是质数,每行每列和是质数
0,1不是质数,2,3是质数
只要把1按X状排列,然后再把第一列的中间那个数改成1即可
#include<iostream>
#include<queue>
#include<map>
#include<utility>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<cmath>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
typedef pair<int, int> P;
ll m;
int main() {
cin >> m;
while (m--)
{
ll a, b;
cin >> a;
ll ans = 0;
for (int i = 0; i < a; i++) {
for (int j = 0; j < a; j++) {
if (i == j||i+j==a-1||(j==0&&i==a/2)|| (i == 0 && j == a / 2))cout << 1 << ' ';
else cout << 0 << ' ';
}
cout << '
';
}
}
}
C. Binary Search
给定一串长度为n的数列,问有多少种排列能用二分法找到pos处的X
我们模拟二分操作,就能知道要找出X的话,
在什么位置需要放大于X的数,什么地方放小于X的数,然后求组合数即可
#include<iostream>
#include<queue>
#include<map>
#include<utility>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<cmath>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
typedef pair<int, int> P;
ll n, x, pos;
ll lm = 0, rm = 0;
const ll mod = 1e9 + 7;
ll inv[10000];
ll f[10000];
ll qpow(ll a, ll b) {
ll res = 1;
a %= mod;
while (b)
{
if (b & 1)res = (res * a) % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
void pre(ll len) {
f[0] = 1;
for (int i = 1; i <= len; i++)
f[i] = i * f[i - 1] % mod;
inv[len] = qpow(f[len], mod - 2);
for (int i = len - 1; i >= 0; i--)inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll A(ll n, ll m) {
if (n < m || n < 0)return 0;
return f[n] % mod * inv[n - m] % mod;
}
int main() {
cin >> n >> x >> pos;
ll l = 0, r = n, mid = -1;
pre(1000 + 5);
ll ans = 1;
while (1)
{
mid = (l + r) / 2;
if (mid == pos) {
l = mid + 1; break;
}
else if (mid > pos) lm++, r = mid;
else rm++, l = mid + 1;
}
while (l<r)
{
r = (l + r) / 2;
lm++;
}
ans = A(n - x, lm) * A(x - 1, rm) % mod * A(n - lm - rm - 1, n - lm - rm - 1) % mod;
cout << ans;
}
D. Bandit in a City
给定一个树和每个点的人数,某时刻根出现强盗,每次行动强盗和所有人都要选其中一个子树走,
最终强盗所在的叶子的人数最小值是多少 强盗和人都倾向于最优解
考虑强盗到达某一节点,如果强盗下到其中一个子节点,其他人就应该都跑到其他节点为最优状况,
所以强盗抓到人数的最好情况是以当前节点为根的子树的和/当前子树的叶子数,
但是不一定能够均匀分配,所以求所有的sum[u]/lev[u]的最值
#include<iostream>
#include<queue>
#include<map>
#include<utility>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<cmath>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
typedef pair<int, int> P;
ll n, m, pos;
ll lm = 0, rm = 0;
const ll mod = 998244353;
ll dat[300000+5];
vector<ll>s[300000 + 5];
const int maxn = 100005;
ll son[300000 + 5];
ll val[300000 + 5];
ll dfs(ll x) {
if (s[x].size() == 0||val[x])return val[x]=dat[x];
ll ans = dat[x];
for (int i = 0; i < s[x].size(); i++) {
ans += dfs(s[x][i]);
}
return val[x] = ans;
}
ll dfs2(ll x) {
if (s[x].size() == 0 || son[x] != 0)return son[x]=1;
ll ans = son[x];
for (int i = 0; i < s[x].size(); i++) {
ans += dfs2(s[x][i]);
}
return son[x] = ans;
}
ll cal(ll x) {
ll ans = -1;
for (int i = 1; i <= n; i++) {
ans = max(ans,(val[i]+son[i]-1) / son[i]);
}
return ans;
}
int main() {
cin >> n;
for (int i = 2; i <= n; i++) {
ll tmp;
cin >> tmp;
s[tmp].push_back(i);
}
for (int i = 1; i <= n; i++)cin >> dat[i];
dfs(1);
dfs2(1);
ll ans = cal(1);
cout << ans;
}
E. Complicated Computations
规定数列的MEX为数列中第一个没有出现的数,求给定数列MEX的MEX
由给定的每个数都小于等于n,想到从1到n枚举,看是否可以是MEX,最后求总的MEX
考虑数字a,如果在两个a的间隔(或者开头到第一个a,最后一个a到结尾)中1到a-1都出现了,那么a就可以当作MEX,
按顺序更新,
令上次a出现的位置为lst[a],当前a的位置是i,只要求1到a-1出现的位置的最小值都大于lst[a]那么他们就都出现了,
a就可以作为MEX的值,后更新lst[a]即可
1要特判
#include<iostream>
#include<queue>
#include<map>
#include<utility>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<cmath>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ll vis[100000 + 5];
ll dat[100000 + 5];
ll val[100001 << 2];
ll lst[100000 + 5];
ll n;
void updata(ll o, ll l, ll r, ll pos, ll n) {
if (l == r)return (void)(val[o] = n);
ll mid = (l + r) / 2;
if (mid >= pos)updata(o << 1, l, mid, pos, n);
else updata(o << 1 | 1, mid + 1, r, pos, n);
val[o] = min(val[o << 1], val[o << 1 | 1]);
}
ll q(ll o, ll l, ll r, ll L, ll R) {
if (l >= L && r <= R) {
return val[o];
}
else {
ll ans = 1000000;
ll mid = l + (r - l)/2;
if (L <= mid)ans=min(ans,q(o << 1, l,mid, L, R));
if (R > mid)ans = min(ans, q(o << 1 | 1, mid + 1, r, L, R));
return ans;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)cin >> dat[i];
for (int i = 1; i <= n; i++) {
if (dat[i] > 1)vis[1] = 1;
if(dat[i]>1)q(1, 1, n, 1, dat[i] - 1);
if (dat[i] > 1 && q(1, 1, n, 1, dat[i] - 1) > lst[dat[i]])vis[dat[i]] = 1;
lst[dat[i]] = i;
updata(1, 1, n, dat[i], i);
}
for (int i = 2; i <= n + 1; i++)
if (q(1, 1, n, 1, i - 1) > lst[i])vis[i] = 1;
ll ans = 1;
while (vis[ans])ans++;
cout << ans;
}