Codeforces Round #610 (Div. 2) 题解
- Temporarily unavailable
- K for the Price of One (Hard Version)
- Petya and Exam
- Enchanted Artifact
- The Cake Is a Lie
Temporarily unavailable
直接计算出 \([c-r, c+r]\) 在 \([a, b]\) 中的范围有多大,然后减掉就可以了。
view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
int main() {
scanf("%d", &T);
while(T--) {
ll a, b, c, r, ans;
scanf("%lld%lld%lld%lld", &a, &b, &c, &r);
if(a>b) swap(a, b);
ans = b-a;
ll over = max(a, min(c+r, b)) - min(b, max(c-r, a));
printf("%lld\n", ans-over);
}
return 0;
}
K for the Price of One (Hard Version)
首先肯定是买最便宜的,由于有 \(k\) 个只能买 \(k\) 个,所以可以看成有两种策略,买 \(1\) 个和买 \(k\) 个,然后用 \(dp[i]\) 表示买了前 \(i\) 个物品的最少花费,然后看给出的钱可以买多少个。
view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 2e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m, k;
int cas, tol, T;
ll dp[maxn];
int a[maxn];
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &n, &m, &k);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) dp[i] = INF;
dp[0] = 0;
sort(a+1, a+1+n);
for(int i=1; i<=n; i++) {
if(i-k>=0)
dp[i] = min(dp[i-1], dp[i-k])+a[i];
else
dp[i] = dp[i-1]+a[i];
}
ll ans = 0;
for(int i=n; i>=1; i--) {
if(dp[i] <= m) {
ans = i;
break;
}
}
printf("%lld\n", ans);
}
return 0;
}
Petya and Exam
由于有一个限制时间 \(t_i\),那么我可以按限制时间 \(t_i\) 排序来完成每一个作业。
令 \(p[i]\) 表示完成 \(i\) 个作业需要的时间,那么我想要完成这 \(i\) 个作业,我所用的时间必须在 \(t_{i+1}\) 以内,这些是必须要完成的作业。
接下来还有一部分剩下的时间,我可以用这些剩余的时间去贪心完成还没到达限制时间的作业,每次先完成简单的,在完成难的。
view
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 2e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
ll n, m;
int cas, tol, T;
struct Node {
ll a, b, p;
bool operator < (Node c) const {
return b<c.b;
}
} node[maxn];
ll p[maxn], a[2];
ll solve(ll time, ll x, ll y) {
ll cnt = 0;
ll oka = min(x, time/a[0]);
cnt += oka;
time -= oka*a[0];
ll okb = min(y, time/a[1]);
cnt += okb;
return cnt;
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%lld%lld%lld%lld", &n, &m, &a[0], &a[1]);
for(int i=1, x; i<=n; i++) {
scanf("%lld", &node[i].p);
node[i].a = a[node[i].p];
}
for(int i=1; i<=n; i++) {
scanf("%lld", &node[i].b);
}
p[0] = 0;
sort(node+1, node+1+n);
node[n+1].b = m+1;
for(int i=1; i<=n; i++) p[i] = p[i-1]+node[i].a;
ll ans = 0, cnt[2] = {0};
// for(int i=1; i<=n; i++) printf("%d%c", node[i].a, i==n ? '\n':' ');
// for(int i=1; i<=n; i++) printf("%d%c", node[i].b, i==n ? '\n':' ');
// for(int i=1; i<=n; i++) printf("%d%c", p[i], i==n ? '\n':' ');
// cout << "=====" << endl;
for(int i=n; i>=0; i--) {
if(p[i] < node[i+1].b)
ans = max(ans, i+solve(node[i+1].b-p[i]-1, cnt[0], cnt[1]));
cnt[node[i].p]++;
}
printf("%lld\n", ans);
}
return 0;
}
Enchanted Artifact
表示 \(D、E\) 题意一直都没读懂,所以这里也讲一下题意。
这是一题交互题,也就是一问一答的形式。题意想要让你猜一个全由 \(a、b\) 组成的字符串,每次你输出一个字符串,题目返回你的字符串和题目的字符串二者之间的编辑距离,要求最多只能问 \(n+2\) 次,并且每次询问的字符串长度不可以超过 \(300\)。
第一次给出一个字符串 \(a\),获得它和答案字符串的编辑距离 \(n\)。考虑如下事情:如果答案字符串存在一个 \(a\),那么这个 \(a\) 一定不变化,只要在两侧插入其他字符即可,那么答案字符串长度就是 \(n+1\)。如果不存在一个 \(a\),那么这个 \(a\) 一定要通过一次操作变成 \(b\),然后在两侧加入其他字符,则答案字符串长度就是 \(n\)。
那么第二步我可以输出长度为 \(n+1\) 并且全为 \(a\) 的字符,获得两者的编辑距离 \(m\),那么如果 \(m == n+1\),答案就一定是第二种,否则就一定是第一种。
此时我们就获得了答案字符串的字符长度和全为 \(a\) 时的编辑距离。所以此时的编辑距离可以理解成当前字符串和答案字符串 \(s[i] \neq t[i]\) 的个数。所以我只要操作每一位,把每一位从 \(a\) 换成 \(b\),看编辑距离会不会变小,就知道了这一位是不是和答案字符串相同了。
view
/***************************************************************
> File Name : e.cpp
> Author : Jiaaaaaaaqi
> Created Time : 2019/12/28 19:37:44
***************************************************************/
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
pii solve() {
cout << "a" << endl;
cin >> n;
if(n == 300) {
for(int i=1; i<=300; i++) cout << "b";
cout << endl;
exit(0);
}
string ans = "";
for(int i=0; i<=n; i++) ans += 'a';
cout << ans << endl;
cin >> m;
if(m == n+1) {
for(int i=1; i<=n; i++) cout << "b";
cout << endl;
exit(0);
} else {
return {n+1, m};
}
}
int main() {
// freopen("in", "r", stdin);
pii pa = solve();
int len = pa.fi, ans = pa.se;
string ask;
for(int i=1; i<=len; i++) ask += 'a';
for(int i=0; ans&&i<len; i++) {
ask[i] = 'b';
cout << ask << endl;
cin >> n;
if(n < ans) ans = n;
else ask[i] = 'a';
}
cout << ask << endl;
return 0;
}
The Cake Is a Lie
把一个 \(n\) 边形割成 \(n-2\) 个三角形,给出这 \(n-2\) 个三角形三个顶点标号,让你构造出 \(p、q\) 数组,\(p\) 数组表示这个 \(n\) 边形顺时针或者逆时针走一圈各个点的标号,\(q\) 数组表示切割三角形的顺序。
分成两步来做,第一步确定这个 \(n\) 边形的标号。我们考虑 \(n\) 边形的 \(n\) 条边一定是在且只在一个三角形内,而通过切割后出现的边,则一定会使用两次。
那么把三角形的边存起来,然后看对于每一个顶点 \(u\),若存在一个从 \(u\) 到 \(v\) 的边,则说明 \(u-v\) 这条边在一个三角形内出现过,那么只要找到每个 \(u\) 和其相连的且只出现一次的 \(v\),把 \(v\) 放在 \(u\) 两侧即可,然后通过 \(dfs\) 一个一个搜出来就可以了。
对于第二步更加简单,想要切下来一个三角形,那么这个三角形一定是两个边在最外侧,一个边还没切割出来,然后去切割这还没被切割出来的边,那么只要通过拓扑排序类似的方法来一个个切就可以了。
view
/***************************************************************
> File Name : e.cpp
> Author : Jiaaaaaaaqi
> Created Time : 2019/12/28 20:48:26
***************************************************************/
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
vector<int> g[maxn];
int p[maxn], q[maxn], pos[maxn];
bool vis[maxn];
struct E {
int a, b, c, cnt;
} e[maxn];
void put(int u, int v) {
if(pos[v]) return ;
int x = pos[u], y;
y = (x-1==0 ? n : x-1);
if(!p[y]) {
p[y] = v;
pos[v] = y;
return ;
}
y = (x+1==n+1 ? 1 : x+1);
if(!p[y]) {
p[y] = v;
pos[v] = y;
return ;
}
}
void dfs(int u) {
if(vis[u]) return ;
vis[u] = true;
for(int i=0, cnt=1; i<g[u].size()-1; i++) {
if(g[u][i] == g[u][i+1]) cnt++;
else {
if(cnt == 1) put(u, g[u][i]), dfs(g[u][i]);
cnt = 1;
}
}
}
map<pii, int> mp, mp2;
vector<int> vv[maxn*10];
void topu() {
queue<int> Q;
int ans = 0;
for(int i=1; i<=n; i++) mp2[{min(p[i], p[i%n+1]), max(p[i], p[i%n+1])}] = 1;
for(int i=1; i<=m; i++) vis[i] = 0;
for(int i=1; i<=m; i++) {
e[i].cnt += mp2[{e[i].a, e[i].b}];
e[i].cnt += mp2[{e[i].a, e[i].c}];
e[i].cnt += mp2[{e[i].b, e[i].c}];
if(e[i].cnt == 2) Q.push(i);
}
while(!Q.empty()) {
int u = Q.front();
Q.pop();
q[++ans] = u;
vis[u] = 1;
pii pa;
if(!mp2[{e[u].a, e[u].b}]) pa = {e[u].a, e[u].b};
if(!mp2[{e[u].a, e[u].c}]) pa = {e[u].a, e[u].c};
if(!mp2[{e[u].b, e[u].c}]) pa = {e[u].b, e[u].c};
mp2[{pa.fi, pa.se}] = 1;
for(auto t : vv[mp[{pa.fi, pa.se}]]) {
e[t].cnt++;
if(e[t].cnt == 2) Q.push(t);
}
}
if(n==3) q[++ans] = 1;
}
int main() {
// freopen("in", "r", stdin);
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
tol = 0, mp.clear(), mp2.clear();
for(int i=1; i<=n; i++) g[i].clear(), vv[i].clear();
for(int i=1; i<=n; i++) p[i] = q[i] = pos[i] = vis[i] = 0;
for(int i=1; i<=n-2; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a>b) swap(a, b);
if(a>c) swap(a, c);
if(b>c) swap(b, c);
g[a].pb(b), g[a].pb(c);
g[b].pb(a), g[b].pb(c);
g[c].pb(a), g[c].pb(b);
if(!mp.count({a, b})) mp[{a, b}] = ++tol, vv[tol].clear();
if(!mp.count({a, c})) mp[{a, c}] = ++tol, vv[tol].clear();
if(!mp.count({b, c})) mp[{b, c}] = ++tol, vv[tol].clear();
vv[mp[{a, b}]].pb(i);
vv[mp[{a, c}]].pb(i);
vv[mp[{b, c}]].pb(i);
e[i] = {a, b, c, 0};
}
for(int i=1; i<=n; i++) g[i].pb(n+1), sort(g[i].begin(), g[i].end());
pos[1] = p[1] = 1, m = n-2;
dfs(1);
topu();
for(int i=1; i<=n; i++) printf("%d%c", p[i], i==n ? '\n':' ');
for(int i=1; i<=m; i++) printf("%d%c", q[i], i==m ? '\n':' ');
}
return 0;
}