(1)题意
高桥每天在S点钟打开他房间的灯,并在T点钟关灯,指示灯亮起时,日期可能会发生改变,判断是否在X点过后30分时亮着。
(2)思路
直接模拟即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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;
- void solve()
- {
- int s,t,x;
- cin >> s >> t >> x;
- for(int i = s;i != t;i ++) {
- if(i == 24) i = 0;
- if(x == i) {
- cout << "Yes";
- return;
- }
- }
- cout << "No";
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
B - Takahashi's Secret (atcoder.jp)
(1)题意
高桥有N个朋友,刚开始x这个朋友这个人会知道这个秘密,然后每个人在第i个位置会告诉p[i]这个位置的人高桥的秘密,问最后高桥的朋友会有多少知道秘密。
(2)思路
对于X这个位置,一直往p[i]这个位置跳即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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],vis[N];
- void solve()
- {
- int n,x;
- cin >> n >> x;
- rep(i,1,n) cin >> p[i];
- int c = 0;
- while(!vis[x]) {
- vis[x] = true;
- c ++;
- x = p[x];
- }
- cout << c;
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
(1)题意
N名学生参加四天考试,每天考试总分300分,现在前三天考试已经结束,让你预测每个学生的总分的排名是否是Top K。
(2)思路
直接把前三门成绩全部相加,然后排个序,对于每个人直接+300看能否达到Top K即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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;
- ll p[N],z[N];
- void solve()
- {
- int n,k;
- cin >> n >> k;
- int x;
- rep(i,1,n) {
- rep(j,1,3) {
- cin >> x;
- p[i] += x;
- }
- z[i] = p[i];
- }
- sort(z + 1,z + 1 + n);
- rep(i,1,n) {
- int idx = upper_bound(z + 1,z + 1 + n,p[i] + 300) - z;
- if(n + 1 - idx < k) cout << "Yes\n";
- else 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;
- }
D - Linear Probing (atcoder.jp)
(1)题意
有一个长为2^20的序列,初始全部位置为-1,对于第Q个查询,会有两种类型。
第一种类型,定义一个Xi,若Axi%N这个位置不为-1,则往下找到第一个不为-1的数组,把那个位置值设置为Xi。第二种类型就是输出低Xi这个位置值是多少。
(2)思路
用一个set维护一下每个为-1的位置,对于第一个类型的查询,我们直接二分一下那个位置即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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 = 2e6 + 10;
- ll v[N];
- void solve()
- {
- set<int> st;
- int n = (1 << 20) - 1;
- rep(i,0,n) {
- v[i] = -1;
- st.insert(i);
- }
- int q;
- n ++;
- cin >> q;
- while(q --) {
- ll ti,xi;
- cin >> ti >> xi;
- if(ti == 2) cout << v[xi % n] << '\n';
- else {
- int cur = xi % n;
- auto it = st.lower_bound(cur);
- if(it != st.end()) {
- v[*it] = xi;
- st.erase(it);
- }
- else {
- it = st.lower_bound(0);
- v[*it] = xi;
- st.erase(it);
- }
- }
- }
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
E - Integer Sequence Fair (atcoder.jp)
(1)题意
计算
。
(2)思路
考虑先计算上面部分的指数
,若不要对下面M产生影响,我们可以使用欧拉降幂,对于
进行快速幂取模998244352即可,然后用下面的再计算一次快速幂取模998244353即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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;
- const ll mod = 998244353;
- using i128 = __int128;
- ll ksm(ll a,ll b,ll p)
- {
- if(!a) return 0;
- i128 rs = 1;
- while(b) {
- if(b & 1) rs = rs % p * a % p;
- a = (i128)a % p * a % p;
- b >>= 1;
- }
- return (ll)rs;
- }
- void solve()
- {
- ll n,k,m;
- cin >> n >> k >> m;
- k %= (mod - 1),m %= (mod);
- ll z = ksm(k,n,mod - 1);
- cout << ksm(m,z,mod) << '\n';
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
(1)题意
给你个H*W的矩形,每个格子里面有一个数,问你选择一个H1*W1的矩形去掉一个H2*W2的矩形后,最多能取多大的值。
(2)思路
二维RMQ问题,因此直接上二维ST即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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 = 1003;
- ll s[N][N],a[N][N],val[N][N];
-
- ll dp[N][N][11][11];
- int num[N];
- void rmq(int n, int m){
- int nn = log2(n), mm = log2(m);
- for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) dp[i][j][0][0] = val[i][j];
- for(int ii=0; ii<=nn; ii++)
- for(int jj=0; jj<=mm; jj++)
- if(ii + jj) {
- for(int i=1; i+(1<
-1 <= n; i++) - for(int j=1; j+(1<
-1 <= m; j++) { - if(ii) dp[i][j][ii][jj] = max(dp[i][j][ii-1][jj], dp[i+(1<<(ii-1))][j][ii-1][jj]);
- else dp[i][j][ii][jj] = max(dp[i][j][ii][jj-1], dp[i][j+(1<<(jj-1))][ii][jj-1]);
- }
- }
- }
- ll query(int x1, int y1, int x2, int y2){
- // ll res = 0;
- // rep(i,x1,x2) rep(j,y1,y2) {
- // res = max(res,val[i][j]);
- // }
- // return res;
- int k1 = log2(x2-x1+1); //num[x2-x1+1];
- int k2 = log2(y2-y1+1); //num[y2-y1+1];
- x2 = x2 - (1<
1; - y2 = y2 - (1<
1; - ll ans1 = max(dp[x1][y1][k1][k2], dp[x1][y2][k1][k2]);
- ll ans2 = max(dp[x2][y1][k1][k2], dp[x2][y2][k1][k2]);
- return max(ans1, ans2);
- }
- ll get(int x1,int y1,int x2,int y2)
- {
- return s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
- }
- void solve()
- {
- int n,m,h1,h2,w1,w2;
- cin >> n >> m >> h1 >> w1 >> h2 >> w2;
- h2 = min(h2,h1),w2 = min(w2,w1);
- rep(i,1,n) {
- rep(j,1,m) {
- cin >> a[i][j];
- s[i][j] = s[i - 1][j] + s[i][j - 1] + a[i][j] - s[i - 1][j - 1];
- }
- }
- rep(i,h2,n) rep(j,w2,m) {
- val[i][j] = get(i - h2 + 1,j - w2 + 1,i,j);
- }
- rmq(n,m);
- ll Ans = 0;
- rep(i,h1,n) rep(j,w1,m) {
- ll s1 = get(i - h1 + 1,j - w1 + 1,i,j);
- ll s2 = query(i - (h1 - h2),j - (w1 - w2),i,j);
- Ans = max(Ans,s1 - s2);
- }
- cout << Ans;
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
G - Digits on Grid (atcoder.jp)
(1)题意
有一个H*W的网格,高桥每次可以把一个棋子移到同一行的某一个位置,青木每次会把棋子移动到同一列的某一个位置,在移动2*N步后,会产生多少个不同的数字序列。
(2)思路
对于这些操作来说,实际上是在二分图上走,把行列抽象成不同点,那我们分别对每一步进行dp,定义dp[S]表示目前经过的某一个数字会到达哪些可用行/列,初始化dp[(1 << H) - 1] = 1。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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 = 11;
- int a[N][N];
- vector<int> row[N][N],col[N][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,k;
- cin >> n >> m >> k;
- k <<= 1;
- rep(i,0,n - 1) rep(j,0,m - 1) {
- char c;
- cin >> c;
- a[i][j] = c - '0';
- }
- rep(i,0,n - 1) rep(j,0,m - 1) {
- row[i][a[i][j]].pb(j);
- col[j][a[i][j]].pb(i);
- }
- vector
dp(1 << n,0) ; - dp[(1 << n) - 1] = 1;
- rep(i,1,k) {
- if(i & 1) {
- vector
ndp(1 << m,0) ; - rep(S,1,(1 << n) - 1) {
- if(!dp[S].val()) continue;
- rep(dig,1,9) {
- int T = 0;
- rep(j,0,n - 1) {
- if(!(S >> j & 1)) continue;
- for(auto p : row[j][dig]) T |= 1 << p;
- }
- ndp[T] += dp[S];
- }
- }
- dp = ndp;
- }
- else {
- vector
ndp(1 << n,0); - rep(S,1,(1 << m) - 1) {
- if(!dp[S].val()) continue;
- rep(dig,1,9) {
- int T = 0;
- rep(j,0,m - 1) {
- if(!(S >> j & 1)) continue;
- for(auto p : col[j][dig]) T |= 1 << p;
- }
- ndp[T] += dp[S];
- }
- }
- dp = ndp;
- }
- }
- Mint Ans = 0;
- for(int i = 1;i < (1 << n);i ++) {
- Ans += dp[i];
- }
- cout << Ans;
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }
(1)题意
给你两个长度为N的整数序列A和C,你可以操作任意次,每次选择一个整数i,使得A[i] + 1,花费Ci元,完成操作后你需要支付K*X元,K是A元素中不同值得个数。
(2)思路
我们对于每一个序列按A为第一关键字排序。考虑某一段数把前面得都变成当前位置得值,那么这个题就转换成了把这个序列划分成多少段得问题。
因此考虑dp[i]表示把前i段划分好后,最少需要花费多少元?
![dp[i] = dp[j] + \sum_{k = j + 1}^{i}(a[i] - a[k]) * c[k] + x](https://1000bd.com/contentImg/2024/03/15/091308328.png)
化简一下
考虑前缀和维护sumC和sumCA,对于有j得项抽出来。
设dp[j] + sumCA[j]为b -sumC[j]为k
发现这个东西可以用斜率优化掉,因此直接上李超树即可。
(3)代码
- #include
- #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
- #define fi first
- #define se second
- #define vi vector
- #define vl vector
- #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;
- namespace OY {
- struct LichaoSegLine {
- double m_k, m_b;
- LichaoSegLine() = default;
- LichaoSegLine(double k, double b) : m_k(k), m_b(b) {}
- double calc(int i) const { return m_k * i + m_b; }
- };
- template <typename Line>
- struct LichaoSegLess {
- bool operator()(const Line &x, const Line &y, int i) const { return x.calc(i) < y.calc(i); }
- };
- template <typename Line = LichaoSegLine, typename Compare = LichaoSegLess
> - struct LichaoSegTree {
- struct LineNode {
- Line m_line;
- LineNode *m_lchild, *m_rchild;
- LineNode(Line line, LineNode *lchild = nullptr, LineNode *rchild = nullptr) : m_line(line), m_lchild(lchild), m_rchild(rchild) {}
- };
- Line m_defaultLine;
- uint64_t m_length;
- Compare m_comp;
- LineNode *m_root;
- void _clear(LineNode *p) {
- // if (p->m_lchild) _clear(p->m_lchild);
- // if (p->m_rchild) _clear(p->m_rchild);
- // delete p;
- }
- LichaoSegTree(uint64_t length = 0, Compare comp = Compare(), Line defaultLine = Line()) : m_comp(comp), m_defaultLine(defaultLine), m_root(nullptr) { resize(length); }
- ~LichaoSegTree() {
- if (m_root) _clear(m_root);
- }
- void resize(uint64_t length) {
- if (m_root) _clear(m_root);
- m_root = (m_length = length) ? new LineNode(m_defaultLine, nullptr, nullptr) : nullptr;
- }
- void add(uint64_t left, uint64_t right, const Line &line) {
- if (right >= m_length) right = m_length - 1;
- if (left > right) return;
- auto dfs = [&](auto self, LineNode *&cur, uint64_t lbound, uint64_t rbound, Line line) -> void {
- if (!cur) cur = new LineNode(m_defaultLine, nullptr, nullptr);
- if (uint64_t mid = (lbound + rbound) / 2; left <= lbound && right >= rbound) {
- if (m_comp(cur->m_line, line, mid)) std::swap(cur->m_line, line);
- if (lbound < rbound)
- if (m_comp(cur->m_line, line, lbound))
- self(self, cur->m_lchild, lbound, mid, line);
- else if (m_comp(cur->m_line, line, rbound))
- self(self, cur->m_rchild, mid + 1, rbound, line);
- } else {
- if (left <= mid) self(self, cur->m_lchild, lbound, mid, line);
- if (right > mid) self(self, cur->m_rchild, mid + 1, rbound, line);
- }
- };
- dfs(dfs, m_root, 0, m_length - 1, line);
- }
- Line query(uint64_t i) const {
- Line res(m_defaultLine);
- auto dfs = [&](auto self, LineNode *cur, uint64_t lbound, uint64_t rbound) -> void {
- if (!cur) return;
- if (m_comp(res, cur->m_line, i))
- res = cur->m_line;
- if (lbound == rbound) return;
- if (uint64_t mid = (lbound + rbound) / 2; i <= mid)
- self(self, cur->m_lchild, lbound, mid);
- else
- self(self, cur->m_rchild, mid + 1, rbound);
- };
- dfs(dfs, m_root, 0, m_length - 1);
- return res;
- }
- };
- template <typename Line = LichaoSegLine, typename Compare = LichaoSegLess
> - LichaoSegTree(uint64_t = 0, Compare = Compare(), Line = Line()) -> LichaoSegTree
; - }
- using i128 = __int128;
- struct Line {
- ll k,b;
- ll calc(ll i) const {
- return i * k + b;
- }
- };
- struct compare {
- bool operator()(const Line &x, const Line &y, i128 i) const {
- ll x_val = x.calc(i), y_val = y.calc(i);
- return x_val > y_val;
- }
- };
- const uint64_t inf = 1e12;
- pair
e[N]; - ll sumC[N],sumCA[N];
- ll dp[N];
- void solve()
- {
- int n,x;
- cin >> n >> x;
- //dp[i]:前i个的最小花费
- //dp[i] = dp[j] + k:[j + 1,i](a[i] - a[k])*c[k] + x
- //dp[i] = dp[j] + a[i] * k:[j + 1,i]c[k] - k:[j + 1,i]:a[k] * c[k] + x
- //dp[i] = dp[j] + a[i] * (sumC[i] - sumC[j]) - sumCA[i] + sumCA[j] + x
- //dp[i] = dp[j] + a[i] * sumC[i] - a[i] * sumC[j] - sumCA[i] + sumCA[j] + x
- //设dp[j] + sumCA[j]为b -sumC[j]为k
- //则dp[i] = b + a[i] * sumC[i] - a[i] * k - sumCA[i] + x
- //根据a[i] query一个最小的值进行转移即可
- OY::LichaoSegTree tr(1000005,compare(),Line{0,inf});
- for(int i = 1;i <= n;i ++) {
- cin >> e[i].fi >> e[i].se;
- }
- sort(e + 1,e + 1 + n);
- for(int i = 1;i <= n;i ++) {
- sumC[i] = sumC[i - 1] + e[i].se;
- sumCA[i] = sumCA[i - 1] + 1ll * e[i].fi * e[i].se;
- }
- tr.add(0,inf,{0,0});
- for(int i = 1;i <= n;i ++) {
- dp[i] = 1ll * e[i].fi * sumC[i] + tr.query(e[i].fi).calc(e[i].fi) - sumCA[i] + x;
- tr.add(0,inf,{-sumC[i],dp[i] + sumCA[i]});
- }
- cout << dp[n] << '\n';
- }
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0),cout.tie(0);
- int T = 1;
- // cin >> T;
- while(T --) solve();
- return 0;
- }