暑假N天乐【比赛篇】 —— 2019牛客暑期多校训练营(第七场)
作者:互联网
以下题解包括:\(A \ \ \ B \ \ \ C \ \ \ D \ \ \ E \ \ \ J\)
另:\(H【Pair】数位dp \ 待补\) 毕竟我还不会
比赛地址: https://ac.nowcoder.com/acm/contest/887#question
【A】 String 最小表示法
给定一个字符串,要把它分成最少段的最小表示法串,输出分段之后的字符串。
从前往后依次枚举,不断缩短长度直到当前前缀为最小表示法即可,然后输出再从当前末尾开始判断。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
char s[205];
string temp;
int l;
int get_min() {
int i = 0, j = 1;
int k = 0;
while(i < l && j < l && k < l) {
int t = temp[(i+k)%l] - temp[(j+k)%l];
if(t == 0) {
k ++;
}
else {
if(t > 0) {
i = i + k + 1;
}
else {
j = j + k + 1;
}
k = 0;
if(i == j) {
j ++;
}
}
}
return i < j ? i : j;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%s", s);
int n = strlen(s);
int pos = 0;
while(1) {
temp = "";
for(int i = pos; i < n; i++) {
temp = temp + s[i];
}
l = temp.length();
while(get_min() != 0) {
l--;
}
pos = pos + l;
for(int i = 0; i < l; i ++) {
cout << temp[i];
}
if(pos == n) {
printf("\n");
break;
}
else {
printf(" ");
}
}
}
return 0;
}
【B】 Irreducible Polynomial 数学
给定一个一元 \(n\) 次方程,问能不能把它分解成连乘的形式。
又是个定理题,次数大于等于 3 一定不行,等于 1 一定可以,等于二的时候需要判断 \(b^2 - 4ac < 0\) 是否成立,若成立,则可以。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int a[30];
int main() {0;
}
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
for(int i = n; i >= 0; i--) {
scanf("%d", &a[i]);
}
if(n >= 3) {
printf("No\n");
continue;
}
if(n == 1) {
printf("Yes\n");
continue;
}
if(a[1]*a[1]-4*a[0]*a[2] < 0) {
printf("Yes\n");
}
else {
printf("No\n");
}
}
return 0;
}
【C】 Governing sand 贪心
我也不知道为什么比赛时候没看到 "c <= 200" 这个条件,然后队友敲了个权值线段树维护,虽然过了也是浪费了挺多时间的,还把学弟坑了...以下是赛后写的正解(大概)。
给定 \(n\) 种树,每种都有它的高度 \(h(\leq1e^9)\),砍倒的费用 \(c(\leq 200)\)以及数量 \(p(\leq 1e^9)\)。现在需要让最高的树的数量占比超过 50%,问最小花费是多少。
其实就是各种排序贪心一下就好了。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5+5;
int n;
ll sum[maxn];
ll cost[205];
ll numh[maxn];
vector<ll> v;
struct node {
ll h, c, p;
bool operator < (const node &q) const {
return h < q.h;
}
}a[maxn];
int getid(ll x) {
return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
int main() {
while(~scanf("%d", &n)) {
v.clear();
for(int i = 1; i <= n; i++) {
scanf("%lld%lld%lld", &a[i].h, &a[i].c, &a[i].p);
v.push_back(a[i].h);
}
sort(a+1, a+1+n);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
memset(sum, 0, sizeof(sum));
memset(numh, 0, sizeof(numh));
for(int i = 1; i <= n; i++) {
int id = getid(a[i].h);
sum[id] += sum[id-1] + 1ll*a[i].p*a[i].c;
numh[id] += numh[id-1] + 1ll*a[i].p;
}
ll ans = 1e18;
memset(cost, 0, sizeof(cost));
int new_n = v.size();
for(int i = 1; i <= n; i++) {
int id = getid(a[i].h);
ll temp = sum[new_n] - sum[id]; // 删掉所有比它高的树的代价
ll num = numh[id] - numh[id-1]; // 这种高度的树的数量
ll num_small = numh[id-1]; // 比他矮的树的数量
// cout << temp << " " << num << " " << num_small << endl;
if(num > num_small) { // 不用砍了
ans = min(ans, temp);
cost[a[i].c] += 1ll*a[i].p;
continue;
}
ll more = num_small - num + 1; // 需要砍掉多少
for(int j = 1; j <= 200; j++) {
if(cost[j] == 0) {
continue;
}
if(more - cost[j] >= 0) {
more -= cost[j];
temp = temp + cost[j]*j;
}
else {
temp = temp + more*j;
more = 0;
}
if(more == 0) {
break;
}
}
cost[a[i].c] += 1ll*a[i].p;
ans = min(ans, temp);
}
printf("%lld\n", ans);
}
return 0;
}
【D】 Number 水题
水题不写了。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int get(int x) {
int res = 0;
while(x) {
res++;
x /= 10;
}
return res;
}
int main() {
int n, p;
while(~scanf("%d%d", &n, &p)) {
int l = get(p);
if(l > n) {
printf("T_T\n");
continue;
}
printf("%d", p);
for(int i = l+1; i <= n; i++) {
printf("0");
}
printf("\n");
}
return 0;
}
【E】 Find the median 线段树
参考:http://keyblog.cn/article-189.html
题目花里胡哨的,其实就是给定两个数组 L,R和一个空序列,对于第 \(i\) 对 LR 来说,把 \([L_i,R_i]\) 中的每个数加入序列,然后输出当前序列中的中位数。
主要是写起来麻烦,一些 +1/-1 会很容易错,尤其是我这种使用 \(vector\) 离散化的,我是多插了一个 -1 让下标从 1 开始,这样或者用数组可以规避很多 +1/-1。具体实现看代码。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 8e5+5;
ll x[maxn], y[maxn];
ll val[maxn<<2], lazy[maxn<<2];
vector<ll> v;
int getid(ll x) {
return lower_bound(v.begin(), v.end(), x) - v.begin();
}
void pushup(int rt) {
val[rt] = val[rt<<1] + val[rt<<1|1];
}
void pushdown(int l, int r, int rt) {
int mid = (l+r) >> 1;
val[rt<<1] += (v[mid]-v[l])*lazy[rt];
val[rt<<1|1] += (v[r]-v[mid])*lazy[rt];
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
void build(int l, int r, int rt) {
if(l == r) {
val[rt] = lazy[rt] = 0;
return ;
}
int mid = (l+r) >> 1;
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt) {
if(L <= l && r-1 <= R) {
val[rt] += (v[r]-v[l]);
lazy[rt] ++;
return ;
}
if(lazy[rt]) {
pushdown(l, r, rt);
}
int mid = (l+r) >> 1;
if(L < mid) {
update(L, R, l, mid, rt<<1);
}
if(R >= mid) {
update(L, R, mid, r, rt<<1|1);
}
pushup(rt);
}
ll query(int l, int r, int rt, ll x) { // 找第 x 大的数
if(l == r-1) {
ll t = val[rt] / (v[r]-v[l]);
return v[l] + (x-1)/t;
}
if(lazy[rt]) {
pushdown(l, r, rt);
}
int mid = (l+r) >> 1;
if(val[rt<<1] >= x) {
return query(l, mid, rt<<1, x);
}
else {
return query(mid, r, rt<<1|1, x-val[rt<<1]);
}
}
int main() {
int n;
scanf("%d", &n);
v.clear();
ll a1, b1, c1, m1;
ll a2, b2, c2, m2;
scanf("%lld%lld%lld%lld%lld%lld", &x[1], &x[2], &a1, &b1, &c1, &m1);
scanf("%lld%lld%lld%lld%lld%lld", &y[1], &y[2], &a2, &b2, &c2, &m2);
for(int i = 3; i <= n; i++) {
x[i] = (a1*x[i-1]+b1*x[i-2]+c1) % m1;
y[i] = (a2*y[i-1]+b2*y[i-2]+c2) % m2;
}
for(int i = 1; i <= n; i++) {
ll tx = x[i];
ll ty = y[i];
x[i] = min(tx, ty) + 1;
y[i] = max(tx, ty) + 1 + 1; // 多 +1 方便区间操作
v.push_back(x[i]);
v.push_back(y[i]);
}
v.push_back(-1);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
int new_n = v.size();
ll sum = 0;
build(1, new_n, 1);
for(int i = 1; i <= n; i++) {
int l = getid(x[i]);
int r = getid(y[i]);
update(l, r-1, 1, new_n, 1);
sum = sum + (v[r] - v[l]);
printf("%lld\n", query(1, new_n, 1, (sum+1)/2));
}
return 0;
}
【J】 A+B problem 水题
其实不是很想把它叫做水题,毕竟把我给卡了,明明 10 行搞定的东西,脑子一抽写了快 100 行,多花了不知道多久...以下代码为赛后补题
水题不写了。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll f(ll x) {
ll res = 0;
while(x) {
res = res*10 + x%10;
x /= 10;
}
return res;
}
int main() {
ll a, b;
int t;
scanf("%d", &t);
while(t--) {
scanf("%lld%lld", &a, &b);
printf("%lld\n", f(f(a)+f(b)));
}
return 0;
}
标签:const,temp,int,天乐,ll,第七场,多校,long,include 来源: https://www.cnblogs.com/Decray/p/11366001.html