赞
踩
D.Tasks - AtCoder Beginner Contest 319
(1)题意
给你一个M行得框框和N个单词,每个单词有一个宽度,每个单词之间应该用一个空格隔开,首位单词不需要,问至少需要多宽才能使得单词不会超过M行。
(2)解题思路
直接二分宽度,然后check即可。
(3)代码实现
- #include <bits/stdc++.h>
- #define rep(i,z,n) for(int i = z;i <= n; i++)
- #define per(i,n,z) for(int i = n;i >= z; i--)
- #define PII pair<int,int>
- #define fi first
- #define se second
- #define vi vector<int>
- #define vl vector<ll>
- #define pb push_back
- #define sz(x) (int)x.size()
- #define all(x) (x).begin(),(x).end()
- using namespace std;
- using ll = long long;
- const int N = 2e5 + 10;
- int L[N];
- int n,m;
- bool check(ll k)
- {
- int cnt = 0;
- ll cur = 0;
- rep(i,1,n) {
- if(k < L[i]) {
- return false;
- }
- }
- rep(i,1,n) {
- if(cur - L[i] - 1 >= 0) {
- cur -= L[i] + 1;
- }
- else {
- cur = k - L[i];
- cnt ++;
- }
- }
- // cout << "???" << k << '\n';
- return cnt <= m;
- }
- void solve()
- {
- cin >> n >> m;
- for(int i = 1;i <= n;i ++) {
- cin >> L[i];
- }
- ll l = 1,r = 1e18;
- while(l <= r) {
- ll mid = (l + r) >> 1;
- if(check(mid)) r = mid - 1;
- else l = mid + 1;
- }
- cout << l << endl;
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
(1)题意
A要从自己家到B家,中间得路段构成是A先走一段路到达站点1,然后做公交到站点n,最后走一段路到B家,每一个站点得公交车会在P[i]倍数得时间发车,需要T[i]得时间才能到达下一个站,现在有q个询问,每个询问给定你起始时间,问最后达到B家得最小时间是多少。
(2)解题思路
考虑每一个P[i]得倍数都会有一些余数,不妨把他们得最小公倍数求出来,然后预处理出0-最小公倍数得起始时间需要花费多少时间到达B家。
(3)代码实现
- #include <bits/stdc++.h>
- #define rep(i,z,n) for(int i = z;i <= n; i++)
- #define per(i,n,z) for(int i = n;i >= z; i--)
- #define PII pair<int,int>
- #define fi first
- #define se second
- #define vi vector<int>
- #define vl vector<ll>
- #define pb push_back
- #define sz(x) (int)x.size()
- #define all(x) (x).begin(),(x).end()
- using namespace std;
- using ll = long long;
- const int N = 2e5 + 10;
- int p[N],t[N];
- ll Ans[N];
- int n,x,y;
- ll calc(ll st)
- {
- st += x;
- for(int i = 1;i < n;i ++) {
- int z = st % p[i];
- if(!z) z = p[i];
- st += p[i] - z;
- st += t[i];
- }
- return st + y;
- }
- void solve()
- {
- cin >> n >> x >> y;
- set<int> pt;
- for(int i = 1;i < n;i ++) {
- cin >> p[i] >> t[i];
- pt.insert(p[i]);
- }
- int cur = 0;
- for(auto x : pt) {
- if(!cur) cur = x;
- else cur = cur * x / __gcd(cur,x);
- }
- for(int i = 0;i < cur;i ++) {
- Ans[i] = calc(i);
- }
- int q;
- cin >> q;
- for(int i = 1;i <= q;i ++) {
- ll v;
- cin >> v;
- int p = v % cur;
- cout << v - p + Ans[p] << '\n';
- }
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
F - Fighter Takahashi (atcoder.jp)
(1)题意
你在一颗树上战斗,起初你的战斗力是1,树上每个点要么是药剂,要么是怪兽,如果是怪兽,你的战斗力大于等于他就可以击败他获取奖励战斗力,如果是药剂你可以使你得战斗力翻g[i]倍,现在问你是否可以从1号节点战败所有怪兽。
(2)解题思路
首先,若是你当前得实力够打怪兽,那么一定是先打得,如果不够了才考虑用药剂。那么一个很明显得思路是,确定一个吃药得顺序,然后bfs一遍看看能不能打完所有怪兽,那么时间复杂度显然是不太行得。所以我们考虑使用状压dp优化这个枚举吃药顺序得过程,状态dp[i]表示吃了i这些药最高能到得战斗力是多少,最后判一下是否大于等于最高战斗力得怪兽即可。
(3)代码实现
- #include <bits/stdc++.h>
- #define rep(i,z,n) for(int i = z;i <= n; i++)
- #define per(i,n,z) for(int i = n;i >= z; i--)
- #define PII pair<int,int>
- #define fi first
- #define se second
- #define vi vector<int>
- #define vl vector<ll>
- #define pb push_back
- #define sz(x) (int)x.size()
- #define all(x) (x).begin(),(x).end()
- using namespace std;
- using ll = long long;
- const int N = 505;
- int t[N],s[N],g[N],p[N];
- vector<int> e[N];
- ll dp[1<<(10)];
- void solve()
- {
- int n,tot = 0;
- cin >> n;
- vector<int> med,pos(n + 1,0);
- int master = 0;
- rep(i,2,n) {
- cin >> p[i] >> t[i] >> s[i] >> g[i];
- if(t[i] == 2) {
- med.pb(i);
- pos[i] = sz(med) - 1;
- tot ++;
- }
- master = max(master,s[i]);
- e[p[i]].pb(i);
- }
- memset(dp,-1,sizeof(dp));
- //dp[i]:表示吃了这些药能达到最大得能量值
- dp[0] = 1;
- rep(i,0,(1<<tot)-1) {
- if(dp[i] != -1) {
- priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>> q;
- q.push({-1,1});
- vector<bool> used(sz(med),false);
- int cnt = 0;
- ll S = 0;
- while(!q.empty()) {
- auto [val,ver] = q.top();
- q.pop();
- if(val > dp[i]) break;
- cnt ++;
- if(t[ver] == 2 && !(i >> pos[ver] & 1)) {
- used[pos[ver]] = true;
- continue;
- }
- if(t[ver] == 1) {
- dp[i] += g[ver];
- S += g[ver];
- }
- for(auto v : e[ver]) {
- if(t[v] == 2) q.push({-1,v});
- else q.push({s[v],v});
- }
- }
- // cout << i << ' ' << dp[i] << '\n';
- if(dp[i] >= master || cnt == n) {
- cout << "Yes" << '\n';
- return;
- }
- rep(j,0,tot-1) {
- if(used[j]) {
- dp[i | (1 << j)] = max(dp[i | (1 << j)],dp[i] * g[med[j]] - S);
- }
- }
- }
- }
- cout << "No" << '\n';
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
G - Counting Shortest Paths (atcoder.jp)
(1)题意
给你一个完全图,删除一些边后,问你是否能从1-N,如果能,请给出最短路径数量。
(2)解题思路
P1. 首先对于最短路径,我们考虑01bfs得特性,一旦有一个点进入了则不会再进入一次,因此我们可以用一个set维护一下未进入得点集,每次对于一个进入得点,扫描一下未进入得点集,若这个点和进入得点之间得边未删除,则可以把这个点加入队列,这样就可以很快得求得最短路径。
P2.现在我们需要考虑路径数量得问题了,考虑将图分成如下形式。
考虑dp[i],表示i为最短路径上的点的方案数是多少。那么显然对于点集为2的点dp[i]等价于所有点集为1的点的方案和-i不能到达的点集为1的点的方案,依次类推求出dp[n]即可。
(3)代码实现
- #include <bits/stdc++.h>
- #define rep(i,z,n) for(int i = z;i <= n; i++)
- #define per(i,n,z) for(int i = n;i >= z; i--)
- #define PII pair<int,int>
- #define fi first
- #define se second
- #define vi vector<int>
- #define vl vector<ll>
- #define pb push_back
- #define sz(x) (int)x.size()
- #define all(x) (x).begin(),(x).end()
- using namespace std;
- using ll = long long;
- const int N = 2e5 + 10;
- set<int> e[N],g[N],pos;
- int dis[N];
- using i64 = long long;
-
- constexpr int P = 998244353;
- // assume -P <= x < 2P
- int Vnorm(int x) {
- if (x < 0) {
- x += P;
- }
- if (x >= P) {
- x -= P;
- }
- return x;
- }
- template<class T>
- T power(T a, i64 b) {
- T res = 1;
- for (; b; b /= 2, a *= a) {
- if (b % 2) {
- res *= a;
- }
- }
- return res;
- }
- struct Mint {
- int x;
- Mint(int x = 0) : x(Vnorm(x)) {}
- Mint(i64 x) : x(Vnorm(x % P)) {}
- int val() const {
- return x;
- }
- Mint operator-() const {
- return Mint(Vnorm(P - x));
- }
- Mint inv() const {
- assert(x != 0);
- return power(*this, P - 2);
- }
- Mint &operator*=(const Mint &rhs) {
- x = i64(x) * rhs.x % P;
- return *this;
- }
- Mint &operator+=(const Mint &rhs) {
- x = Vnorm(x + rhs.x);
- return *this;
- }
- Mint &operator-=(const Mint &rhs) {
- x = Vnorm(x - rhs.x);
- return *this;
- }
- Mint &operator/=(const Mint &rhs) {
- return *this *= rhs.inv();
- }
- friend Mint operator*(const Mint &lhs, const Mint &rhs) {
- Mint res = lhs;
- res *= rhs;
- return res;
- }
- friend Mint operator+(const Mint &lhs, const Mint &rhs) {
- Mint res = lhs;
- res += rhs;
- return res;
- }
- friend Mint operator-(const Mint &lhs, const Mint &rhs) {
- Mint res = lhs;
- res -= rhs;
- return res;
- }
- friend Mint operator/(const Mint &lhs, const Mint &rhs) {
- Mint res = lhs;
- res /= rhs;
- return res;
- }
- friend std::istream &operator>>(std::istream &is, Mint &a) {
- i64 v;
- is >> v;
- a = Mint(v);
- return is;
- }
- friend std::ostream &operator<<(std::ostream &os, const Mint &a) {
- return os << a.val();
- }
- };
- void solve()
- {
- int n,m;
- cin >> n >> m;
- for(int i = 1;i <= m;i ++) {
- int u,v;
- cin >> u >> v;
- e[u].insert(v);
- e[v].insert(u);
- }
- for(int i = 2;i <= n;i ++) {
- pos.insert(i);
- }
- memset(dis,0x3f,sizeof(dis));
- dis[1] = 0;
- queue<int> q;
- q.push(1);
- while(!q.empty()) {
- int v = q.front();
- q.pop();
- auto nps = pos;
- for(auto x : nps) {
- if(!e[v].count(x) && pos.count(x)) {
- dis[x] = dis[v] + 1;
- pos.erase(x);
- q.push(x);
- }
- }
- }
- if(dis[n] >= n) {
- cout << -1 << '\n';
- return;
- }
- for(int i = 1;i <= n;i ++) {
- if(dis[i] <= n) g[dis[i]].insert(i);
- }
- vector<Mint> dp(n + 1,0),s(n + 1,0);
- dp[1] = 1;
- for(int i = 0;i < n;i ++) {
- if(i >= 1) {
- for(auto x : g[i]) {
- dp[x] += s[i];
- }
- }
- for(auto x : g[i]) {
- s[i + 1] += dp[x];
- for(auto y : e[x]) {
- if(dis[y] == dis[x] + 1) {
- dp[y] -= dp[x];
- }
- }
- }
- }
- cout << dp[n];
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。