A.DFS搜索
简单遍历判断是否出现过即可
void solve() {
string str;
cin >> n;
cin >> str;
int s = 0, s1 = 0;
for (int i = 0; str[i]; i++) {
if (str[i] == 'D' && s == 0) s++;
if (str[i] == 'F' && s == 1) s++;
if (str[i] == 'S' && s == 2) s++;
if (str[i] == 'd' && s1 == 0) s1++;
if (str[i] == 'f' && s1 == 1) s1++;
if (str[i] == 's' && s1 == 2) s1++;
}
if (s == 3)cout << "1 ";
else cout << "0 ";
if (s1 == 3) cout << "1\n";
else cout << "0\n";
}
B.关鸡
有0,1,2,3三种情况,用map来存储,方便判断该点位上是否有火,op[1]存储第一行,op[2]存储第二行。
0:(1,0)的左右两边都存在着直接上下挨着或者角对角挨着的,无需添加
1:两边其中一边的被堵住了,另一边有火但是没有堵住
2:一边被堵住,另一边没有火
3:两边都没有火,此时只需要在(1,1)(1,-1)(2,0)加上就可以了
ll n, m, a[N], b[N], c[N], d[N];
void solve() {
map<ll, ll>op[3];
ll z = 0, y = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i];
if (b[i] < 0) z++;
if (b[i] > 0) y++;
if (a[i] == 1) {
op[1][b[i]] = 1;
}
else {
op[2][b[i]] = 1;
}
}
ll ans = 0;
bool tr1 = 0, tr2 = 0;
for (auto it : op[1]) {
ll s = it.first;
if (op[2][s] || op[2][s - 1] || op[2][s + 1]) {
if (s < 0) tr1 = 1;
else tr2 = 1;
}
}
if (tr1 && tr2) ans = 0;
else if (!tr1 && !tr2) {
if (op[2][0]) ans = 2;
else if (op[1][1] && op[1][-1]) ans = 1;
else if (op[1][1] || op[1][-1]) ans = 2;
else if (z && y) ans = 2;
else ans = 3;
}
else {
if (tr1) {
if (op[2][0]) ans = 1;
else {
if (y) ans = 1;
else ans = 2;
}
}
else {
if (op[2][0]) ans = 1;
else {
if (z) ans = 1;
else ans = 2;
}
}
}
cout << ans << '\n';
}
C.按闹分配
将数组a排序,从小到大就是合理安排的顺序。然后,求前缀和
二分寻找最佳插队位置,多出来的不满意度就是tc乘以鸡插队位置后面的人数,判断是否小于等于m。
ll n, q,m,tc, a[N], sum[N], s[N], d[N];
bool check(ll nb) {
if ((n - nb) * tc <= m) return true;
else return false;
}
void solve() {
cin >> n >> q >> tc;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i];
}
for (int i = 1; i <= q; i++) {
cin >> m;
ll l = -1, r = n + 1;
while (l + 1 < r) {
ll mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
cout << sum[r]+tc << "\n";
}
}
E.本题又主要考察了贪心
深搜,对三种情况都进行搜索。寻找最靠前的排名即可。
ll n, m, a[N],u[N],v[N];
vector<PII> op;
ll ans = 0;
void dfs(int k) {
if (k > m) {
ll tol = 0;
map<int, int>op;
for (int i = 2; i <= n; i++) {
if (a[i] > a[1])op[i]++;
}
for (auto it : op) {
tol += it.second;
}
ans = min(ans, tol + 1);
op.clear();
return;
}
a[u[k]] += 3;
dfs(k + 1);
a[u[k]] -= 3;
a[u[k]] += 1, a[v[k]] += 1;
dfs(k + 1);
a[u[k]] -= 1;
a[v[k]] -= 1;
a[v[k]] += 3;
dfs(k + 1);
a[v[k]] -= 3;
return;
}
void solve() {
ans = 1000;
cin >> n>>m;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= m; i++) {
cin >> u[i] >> v[i];
}
dfs(1);
cout << ans << "\n";
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
F.鸡数题
一道很裸的求第二类斯特林数题,我当时只有二维递推(O(n*m))的板子,赛时找时间复杂度低的没找到(痛哉!)
#include "bits/stdc++.h"
using namespace std;
using i64 = long long;
constexpr int P = 1000000007;
i64 *fac, *ifac;
//快速幂
i64 power(i64 a, i64 b, int p = P) {
i64 res = 1;
for (; b; b >>= 1, a = a * a % p) {
if (b & 1) {
res = res * a % p;
}
}
return res;
}
//求逆元
i64 inv(i64 x) {
return power(x, P - 2);
}
//预处理阶乘与阶乘逆元
void init(int N) {
fac = new i64 [N + 1];
ifac = new i64 [N + 1];
fac[0] = 1;
for (int i = 1; i <= N; i++) {
fac[i] = fac[i - 1] * i % P;
}
ifac[N] = inv(fac[N]);
for (int i = N - 1; i >= 0; i--) {
ifac[i] = ifac[i + 1] * (i + 1) % P;
}
}
//求组合数
i64 C(int n, int m) {
if (m < 0 || m > n || n < 0) {
return 0;
}
return fac[n] * ifac[m] % P * ifac[n - m] % P;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
init(m);
i64 ans = 0;
for (int k = 0; k <= m; k++) {
if (k % 2 == 0) {
ans = (ans + C(m, k) * power(m - k, n) % P) % P;
} else {
ans = (ans - C(m, k) * power(m - k, n) % P + P) % P;
}
}
cout << ans * ifac[m] % P << '\n';
return 0;
}
G.why买外卖
数据范围不大,根据a[i]进行排序,然后遍历预处理各个优惠下一共减去多少金额,随后遍历每一种优惠,取最大值。
ll n, m, a[N], b[N],c[N],d[N];
void solve() {
vector<pair<ll, ll>>op;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
op.push_back({ a[i],b[i] });
}
sort(op.begin(), op.end());
ll s = 0,sum=0,ans=m;
c[0] = 0, d[0] = 0;
for (auto it : op) {
if (it.first != d[s]) {
d[++s] = it.first;
c[s] = c[s - 1] + it.second;
}
else {
c[s] += it.second;
}
}
for (int i = 1; i <= s; i++) {
sum = c[i] + m;
if (sum >= d[i]) ans = max(ans, sum);
}
cout << ans << "\n";
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
I.It's bertrand paradox. Again!
第一种圆生成时不受r的限制,比较分散,第二种圆生成的x,y会比较接近50,所以比较和50*50*2*n的大小关系就好了
int main()
{
int n;
cin >> n;
int cnt1 = 0;
ll sum1 = 0;
ll sum2 = 50 * 50 * n * 2;
while (n--)
{
int x, y, r;
cin >> x >> y >> r;
sum1 += x * x + y * y;
}
if (sum1 > sum2) cout << "bit-noob\n";
else cout << "buaa-noob\n";
return 0;
}
L.要有光
光源放在黑线与地面交点就是最优解,会形成一个上底为2w,下底为4w,高为c的梯形,输出其面积即可
double c, d, h, w;
void solve() {
double ans = 0;
cin >> c >> d >> h >> w;
ans = 6.0 * w * c / 2;
printf("%.5lf\n", ans);
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
M.牛客老粉才知道的秘密
n取余6等于0的话,向左向右都是相同的n/6个数字。
不等于0的话,向左向右分别是不相同的n/6个数字。
可以自行模拟一下。
ll n, a[N];
map<ll,ll>op;
void solve() {
ll ans = 0;
cin >> n;
if (n % 6 == 0) ans = n / 6;
else ans = n / 6 * 2;
cout << ans << "\n";
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}