Educational Codeforces Round 80 (Rated for Div. 2)
A. Deadline
如果n>=d 直接yes
否则对于公式
\(x+ceil(d/(x+1))<=n\)
两边同时乘以x+1
会得到一个关于x的一元二次方程,
通过求根公式解出较小的那一个根x1,
然后在\(x1+-3\) 的范围内找到\(x+ceil(d/(x+1))\) 的最小值与n比较即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int t; ll n, d; ll check(ll x) { return x + ceil(1.0 * d / (x + 1)); } typedef long double ld; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); // gbtb; cin >> t; while (t--) { cin >> n >> d; if (d <= n) { cout << "YES" << endl; } else { int isok = 0; ld b = 1 - n; ld c = d - n; ld xw = (-b - sqrtl(b * b - 4.0 * c)) * 0.5; ll xx = ll(xw); ll w = inf; repd(i, max(0ll, xx - 3), min(n * 1ll, xx + 3)) { w = min(w, check(i)); } if (w <= n) { isok = 1; } if (isok) { cout << "YES" << endl; } else { cout << "NO" << endl; } } } return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
B. Yet Another Meme Problem
通过打表可以发现
满足 \(a \cdot b + a + b = conc(a, b)\) 的b 为9 ,99,999,9999...等等
所以答案即为 A*F(B)
F(B) 为 <=B 的 9 ,99,999,9999...等等的个数
F(B) 的求法非常简单。
int t; ll a, b; ll F(ll x) { ll res = 0ll; ll base = 9ll; while (base <= x) { base *= 10; base += 9; res++; } return res; } int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); gbtb; cin >> t; while (t--) { cin >> a >> b; a *= F(b); cout << a << endl; } return 0; }
C. Two Arrays
设\(dp1[i][j]\) 为长度为i,以j为结尾的单调不下降序列方案数
设\(dp2[i][j]\) 为长度为i,以j为结尾的单调不上升序列方案数
当j1>=j2 时 以j1为结尾的单调不下降序列和以j2为结尾的单调不上升序列
自动满足:
- ai≤bi for any index ii from 11 to mm;
- array a is sorted in non-descending order;
- array b is sorted in non-ascending order.
然后扫一遍计算答案即可,可以用前缀和来优化,但是这个数据范围没啥必要。
ll dp1[11][1111]; ll dp2[11][1111]; ll n; ll m; const ll mod = 1e9 + 7; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); cin >> n >> m; repd(i, 1, n) { dp1[1][i] = 1; dp2[1][i] = 1; } repd(i, 2, m) { repd(j, 1, n) { repd(k, 1, j) { dp1[i][j] += dp1[i - 1][k]; dp1[i][j] %= mod; } repd(k, j, n) { dp2[i][j] += dp2[i - 1][k]; dp2[i][j] %= mod; } } } ll ans = 0ll; repd(i, 1, n) { repd(j, 1, i) { ans += dp2[m][i] * dp1[m][j] % mod; ans %= mod; } } cout << ans << endl; return 0; }
D. Minimax Problem
极小极大问题 普遍容易通过转化为二分极小值,然后验证可行性的问题。
本题也不例外,我们二分\(\min \limits_{k = 1}^{m} b_k\) 的数值mid。
然后去check 是否存在两个数组满足此条件。
check的方法如下:
我们遍历这n个数组,对于第i个数组的第j个数a(i,j) 是否大于等于mid用一个int整数进行二进制的状态压缩表示,然后将int数值加入一个unordered_set 中。
然后对unset中的元素进行两两测试是否按位与起来满足 m个数均为1.
为什么要用unset呢?
紧扣题目的数据范围,m<=8, 那么对于每一次check一共也就只有 2^8 个情况,
两两测试的时候最大也就是2^16次,依次来降低时间复杂度。
二分的时间复杂度时O(1e9)
check的时间复杂度为O(n*m+2^16)
总时间复杂度为:\(O(log_2(1e9)*(n*m+2^{16}))\)
#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n, m; int a[300010][9]; unordered_set<int> st; int t1, t2; bool check(int x) { st.clear(); int t; repd(i, 1, n) { t = 0; repd(j, 1, m) { if (a[i][j] >= x) { t |= (1 << (j - 1)); } } st.insert(t); } for (auto y : st) { for (auto z : st) { if ((y | z) == (1 << m) - 1) { t1 = y; t2 = z; return 1; } } } } int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); du2(n, m); repd(i, 1, n) { repd(j, 1, m) { du1(a[i][j]); } } int l = 0; int r = 1e9; int mid; int ans; while (l <= r) { mid = (l + r) >> 1; if (check(mid)) { l = mid + 1; ans = mid; } else { r = mid - 1; } } int ans1, ans2; repd(i, 1, n) { int t = 0; repd(j, 1, m) { if (a[i][j] >= ans) { t |= (1 << (j - 1)); } } if (t == t1) { ans1 = i; } if (t == t2) { ans2 = i; } } printf("%d %d\n", ans1, ans2 ); return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
E. Messenger Simulator
对于n个数的数组,我们先初始为 n,n-1,n-2,,,,3 ,2,1 的情况 (即n~1的降序排列)
然后把给定的m个数依次放在数组的尾部。
例如样例1 为:
5 4 3 2 1 3 5 1 4
定义数组vis[i] 代表数字i上一次出现在哪个位置,初始为0。
我们维护两个数组 be[i] 代表数字i出现的最前的位置,ed[i] 代表数字i 出现 的最后的位置。
如果有把数字i提前到第一位,be[i]=1,否则be[i]=i
ed[i] 为上述数组中紧挨着的两个i之间的数字种类数,或者最后一个数字i到结束有多少种类的数字。
因为如果出现第2次以及以上次数i时,证明将数字i提到数组的最前端了,那么i之前的位置一定是一个偏后面的位置,我们维护ed[i]的最大值即可。
至于“ed[i]的另一个情况,最后一个数字i到结束有多少种类的数字”,可以通过样例自行理解一下。
因为询问的区间均为有序的区间,所以可以直接用树状数组进行维护即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n, m; int a[maxn]; int tree[maxn]; int lowbit(int x) { return x & (-x); } void add(int pos, int val) { while (pos < maxn) { tree[pos] += val; pos += lowbit(pos); } } int ask(int pos) { int res = 0; while (pos>0) { res += tree[pos]; pos -= lowbit(pos); } return res; } int be[maxn]; int ed[maxn]; int vis[maxn]; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); du2(n, m); repd(i, 1, n) { a[i] = n - i + 1; } repd(i, n + 1, n + m) { du1(a[i]); be[a[i]] = 1; } repd(i, 1, n) { if (!be[i]) { be[i] = i; } } repd(i, 1, n + m) { if (!vis[a[i]]) { add(i, 1); } else { add(vis[a[i]], -1); add(i, 1); } // chu(i); if (vis[a[i]])ed[a[i]] = max(ed[a[i]], ask(i) - ask(vis[a[i]] - 1)); vis[a[i]] = i; } repd(i, 1, n) { ed[i] = max(ed[i], ask(n + m) - ask(vis[i] - 1)); } repd(i, 1, n) { printf("%d %d\n", be[i], ed[i] ); } return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
来源:https://www.cnblogs.com/qieqiemin/p/12199373.html