文章目录
A. DFS搜索
从前往后遍历字符串,根据字母出现顺序进行判断,时间复杂度 O ( n ) O(n) O(n)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
int f = 0, F = 0;
for(int i = 0;i < s.size();i++)
{
if(f == 0 && s[i] == 'd')
f++;
if(f == 1 && s[i] == 'f')
f++;
if(f == 2 && s[i] == 's')
f++;
if(F == 0 && s[i] == 'D')
F++;
if(F == 1 && s[i] == 'F')
F++;
if(F == 2 && s[i] == 'S')
F++;
}
if(F == 3)
cout << "1 ";
else
cout << "0 ";
if(f == 3)
cout << "1" << '\n';
else
cout << "0" << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
B. 关鸡
记录下所有位置,遍历,注意 ( 1 , 1 ) , ( 1 , − 1 ) , ( 2 , 0 ) (1,1),(1,-1),(2,0) (1,1),(1,−1),(2,0)三个位置,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e5 + 10;
const int INF = 1e18;
const ll mod = 998244353;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
set<pii> s;
int l = 2, r = 2;
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
int x, y;
cin >> x >> y;
s.insert({x, y});
if(y <= 0) l = 1;
if(y >= 0) r = 1;
}
for(int i = -1;i <= 1;i++)
{
for(auto p : s)
{
int x = p.first,y = p.second;
if(s.count({x ^ 3, y + i}))
{
if(y < 0) l = 0;
if(y > 0) r = 0;
}
}
}
int ans = 3;
if(s.count({2, 0})) ans--;
if(s.count({1, 1})) ans--;
if(s.count({1, -1})) ans--;
cout << min(l + r, ans) << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
C. 按闹分配
不难得出,当办事时间从小到大排时总的不满意度 S S S最小
令插队后排在鸡后面的人数 x x x, S c − S m i n S_c - S_{min} Sc−Smin即为 x ∗ t c x * t_c x∗tc,所以我们只需要二分找到鸡后面能排的最大人数,再加上预处理出的前若干个人的办事时间的前缀和即可,时间复杂度 O ( q l o g n ) O(qlogn) O(qlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int t[N];
void solve()
{
int n, q, tc;
cin >> n >> q >> tc;
for(int i = 1;i <= n;i++)
cin >> t[i];
sort(t+1,t+n+1);
for(int i = 1;i <= n;i++)
t[i] += t[i - 1];
while(q--)
{
int now;
cin >> now;
int l = 0, r = n;
while(l <= r)
{
int mid = (l + r) / 2;
if(mid * tc <= now)
l = mid + 1;
else
r = mid - 1;
}
cout << t[n - l + 1] + tc << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
D. 数组成鸡
首先我们要知道,一个绝对值小于等于 1 e 9 1e9 1e9的数最多由不超过二十个不同的数相乘得来
所以我们只需要处理题目中给出不同数个数不超过二十个的情况
由于数值很小,所以我们可以遍历这些数,每次的操作次数为当前这个数 + ( − 4 e 4 , 4 e 4 ) +(-4e4,4e4) +(−4e4,4e4)
注意,询问值是 0 0 0时必定可行,时间复杂度 O ( 400 1 0 9 + q l o g n ) O(400\sqrt{10^9} + qlogn) O(400109+qlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n, q;
cin >> n >> q;
map<int, int> cnt;
for(int i = 1;i <= n;i++)
{
int tt;
cin >> tt;
cnt[tt]++;
}
vector<pii> a;
for(auto x : cnt)
a.push_back(x);
set<int> s;
s.insert(0);
if(a.size() <= 20)
{
int M = 4e4;
for(int k = 0;k < a.size();k++)
{
for(int i = -M;i <= M;i++)
{
int now = 1;
int cur = i - a[k].first;
for(auto j : a)
{
int v = j.first + cur;
if(v == 0)
continue;
for(int t = 1;t <= j.second;t++)
{
now = now * v;
if(abs(now) > 1e9)
break;
}
if(abs(now) > 1e9)
break;
}
if(abs(now) <= 1e9)
s.insert(now);
}
}
}
while(q--)
{
int x;
cin >> x;
if(s.count(x))
cout << "Yes" << '\n';
else
cout << "No" << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
E. 本题又主要考察了贪心
由于数据较小,直接 d f s dfs dfs枚举每个情况即可,时间复杂度 O ( 3 m T ) O(3^{m}T) O(3mT)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[100], b[100], c[100], ans;
int n, m;
void dfs(int now)
{
if(now == m + 1)
{
int cnt = 1;
for(int i = 2;i <= n;i++)
{
if(a[i] > a[1])
cnt++;
}
ans = min(ans, cnt);
return;
}
a[b[now]] += 3;
dfs(now + 1);
a[b[now]] -= 3;
a[c[now]] += 3;
dfs(now + 1);
a[c[now]] -= 3;
a[b[now]]++;
a[c[now]]++;
dfs(now + 1);
a[b[now]]--;
a[c[now]]--;
}
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 >> b[i] >> c[i];
dfs(1);
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
F. 鸡数题
第二类斯特林数S(n,m)的定义为: n n n个有区别球放到 m m m个无区别盒子
这题题意可以理解为有 n n n个 1 1 1,把这些 1 1 1分成 m m m份,问有多少种分法,那如何与第二类斯特林数相联系呢
我们来看第二个条件,对于任意的整数 1 ≤ i ≤ m − 1 , a i < a i + 1 1≤i≤m−1,a_i<a_{i+1} 1≤i≤m−1,ai<ai+1,这说明将 n n n个有区别球放到 m m m个无区别盒子后对每一种方案进行排序,所得到的即为题目这种情况,所以我们直接套第二类斯特林数的公式,时间复杂度 O ( m ) O(m) O(m)
S ( n , m ) = 1 m ! ∑ k = 0 m ( − 1 ) k C ( m , k ) ( m − k ) n S(n,m) = \frac{1}{m!}\sum^{m}_{k=0}(-1)^{k}C(m,k)(m-k)^{n} S(n,m)=m!1∑k=0m(−1)kC(m,k)(m−k)n
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int fac[N], infac[N];
ll C(ll n,ll m){//n个数选m个数
return fac[n] * infac[n - m] % mod * infac[m] % mod;
}
inline ll binpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return res;
}
int cnt;
int n, m;
void solve()
{
cin >> n >> m;
int now = 0, fh = 1;
for(int k = 0;k <= m;k++)
{
now = (now + fh * C(m, k) % mod * binpow(m - k, n) % mod) % mod;
fh = fh * (-1);
}
for(int i = 1;i <= m;i++)
now = now * binpow(i, mod - 2) % mod;
cout << (now + mod) % mod << '\n';
}
signed main()
{
fac[0] = 1;
infac[0] = 1;
for (int i = 1; i <= 1e6;i++){
fac[i] = i * fac[i - 1] % mod;
infac[i] = binpow(fac[i], mod - 2);
}
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
G.why买外卖
按照优惠券的要求额度从小到大排序,再进行遍历
令初始价格为手上有的钱,判断当前手上的钱是否满足要求额度,如果满足则加上当前优惠券的减去额度,如果不满足则将当前优惠券的减去额度加到下一张优惠券上,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
struct sj
{
int a, b;
} x[N];
bool cmp(sj x, sj y)
{
return x.a < y.a;
}
void solve()
{
int n, m;
cin >> n >> m;
for(int i = 1;i <= n;i++)
cin >> x[i].a >> x[i].b;
sort(x+1,x+n+1,cmp);
for(int i = 1;i <= n;i++)
{
if(m + x[i].b >= x[i].a)
m += x[i].b;
else
x[i + 1].b += x[i].b;
}
cout << m << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
H. 01背包,但是bit
背包最大载重为对于 W m W_m Wm二进制数的每位 1 1 1,当我们令这位 1 1 1为 0 0 0后把剩下的二进制数分成前面和后面两个部分
对于前面那一部分二进制,必须要求与 W m W_m Wm的每位都相同。对于后面那一部分二进制,没有强制要求,因为这位 1 1 1已经被我们要求为 0 0 0,所以无论如何后面怎么取,最后得到的新二进制数 W W W肯定是小于 W m W_m Wm的
有一个需要注意的是,我们要计算总重量为 W m W_m Wm时的最大价值
每次拿入背包,判断当前重量 w i w_i wi的二进制数 1 1 1位是不是 W W W的二进制数 1 1 1位的子集即可,如果是子集则可以加入背包,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int v[N], w[N];
int n, W, ans;
void check(int x)
{
int cnt = 0;
for(int i = 1;i <= n;i++)
{
if((x & w[i]) == w[i])
cnt += v[i];
}
ans = max(ans, cnt);
}
void solve()
{
ans = 0;
cin >> n >> W;
for(int i = 1;i <= n;i++)
cin >> v[i] >> w[i];
check(W);
for(int i = 30;i >= 0;i--)
{
if((1 << i) & W)
check((W ^ (1 << i)) | ((1 << i) - 1));
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
I. It’s bertrand paradox. Again!
一个人是不满足的话重新生成 x x x和 y y y,另一个人是不满足的话重新生成 r r r
我们直接来看生成圆的区间, x x x和 y y y都在 [ − 100 , 100 ] [-100,100] [−100,100],我们取这个平面的四个角落,边长都为 10 10 10,那么一次生成随机数落在这四个角落里的概率是多少呢, 10 ∗ 10 ∗ 4 200 ∗ 200 = 1 100 \frac{10*10*4}{200*200}=\frac{1}{100} 200∗20010∗10∗4=1001
因为生成圆的数量固定为 1 0 5 10^5 105,所以理论上第二个人生成的圆中,有 1000 1000 1000个落在角落里,而第一个人生成的圆落在角落里的数目要远远小于这个值,时间复杂度 O ( n ) O(n) O(n)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n;
cin >> n;
int a, b, c, cnt = 0;
for(int i = 1;i <= n;i++)
{
cin >> a >> b >> c;
if((abs(100 - a) <= 10 || abs(-100 - a) <= 10) && (abs(100 - b) <= 10 || abs(-100 - b) <= 10))
cnt++;
}
if(cnt > 400)
cout << "bit-noob" << '\n';
else
cout << "buaa-noob" << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
K. 牛镇公务员考试
题面简直是非常难理解,简单的说就是一题的答案决定下一题的答案,问所有题都答对有多少种情况,答案对 998244353998244353 998244353998244353 998244353998244353取模
一道题决定另一道题,总共有 n n n道题和 n n n个决定关系,而且决定关系是单向的,那我们就能想到内向基环树。
我们把题目抽象为图形,一个有向图,里面有若干的环和环上的链
令所求 a n s = 1 ans=1 ans=1
对于每个环上的链,由于决定关系都是前一个决定后一个,所以答案都是唯一的,对 a n s ans ans没影响
对于每个环,我们可以随便选一个点作为起点,然后让起点选项为 A ∼ E A\sim E A∼E,再沿着环进行遍历,如果最后推出的起点选项确实为开始时候选的那个选项,那么这个环的可行方案 r e s = r e s + 1 res = res + 1 res=res+1,由于选项个数为 5 5 5,所以每个环的可行方案为 [ 0 , 5 ] [0,5] [0,5],每次解决完一个环后, a n s = a n s ∗ r e s % m o d ans = ans * res \% mod ans=ans∗res%mod即可,时间复杂度 O ( n ) O(n) O(n)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e5 + 10;
const int INF = 1e18;
const ll mod = 998244353;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n;
cin >> n;
vector<int> a(n+5), vis(n+5, 0);
vector<string> s(n+5);
for(int i = 1;i <= n;i++)
cin >> a[i] >> s[i];
int ans = 1;
for(int i = 1;i <= n;i++)
{
int j = i;
vector<int> v;
while(!vis[j])
{
vis[j] = 1;
v.push_back(j);
j = a[j];
}
auto pos = find(all(v), j);
if(pos != v.end())
{
int res = 0;
v.erase(v.begin(), pos); // 去掉环上的链
for(int k = 0;k < 5;k++)
{
int now = k;
for(auto u : v)
now = (s[u][now] - 'A');
if(k == now)
res++;
}
ans = ans * res % mod;
}
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
L. 要有光
一开始读错题目了,以为要求计算墙上黑暗的最大面积…
地上的最大未被着照亮面积为梯形,直接计算即可,时间复杂度 O ( T ) O(T) O(T)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int c, d, h, w;
cin >> c >> d >> h >> w;
cout << w * c * 3 << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
M. 牛客老粉才知道的秘密
好吧我不是老粉所以不知道秘密(
直接在纸上画一下 n n n是不是 6 6 6的倍数的两种情况,输出答案即可,时间复杂度 O ( T ) O(T) O(T)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e6 + 10;
const int INF = 1e18;
const ll mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n;
cin >> n;
if(n % 6 == 0)
cout << n / 6 << '\n';
else
cout << n / 6 * 2 << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}