人懒,几天还没补完所有。。。不太会用这个写文章所以写的有点丑,请见谅
A-巨木之森
B-乐团派对
这题使用DP,将a[i]从小到大排列,dp[i]表示前i个人最多可以组成的乐队数量,我们每次满足第I个人的要求,那么dp[i]=dp[i-a[i]]+1,现在来分析一下其合理性,如果i<a[i],则必然是无法凑一个队的,这时dp[i]=0,当i>=arr[i]时,满足第i人的要求,则剩下i-a[i]人,当然,我们最后一队还可以取a[i]+1,a[i]+2…,但我们dp表示的是i人最多多少个人,最后一队队数始终是1,所以人数应该达到最小,满足最后一队后剩下i-a[i]人,前面我们也经过了相同的处理:恰好满足第i-a[i]人的要求,如此一直往前推,一直到最后出现恰好分配完和还有剩余的情况,如果还有剩余,随便丢进哪一队都可以,所以没有影响。
ac代码
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
bool cmp(int a, int b) {
return a > b;
}
const int N = 1e5 + 100;
int arr[N];
int dp[N];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> arr[i];
sort(arr + 1, arr + 1 + n);
if (arr[n] > n) {
cout << -1 << endl;
return 0;
}
for (int i = 1; i <= n; i++) {
if (arr[i] <= i) {
dp[i] = dp[i - arr[i]] + 1;
}
}
if (dp[n] == 0) cout << -1 << endl;
else cout << dp[n] << endl;
return 0;
}
C-光玉小镇
D-巅峰对决
我们注意到任意的两个数都是不同的,所以但区间内的最大值-最小值=r-l,我们可以用线段树维护区间的最大值和最小值
ac代码
#include<iostream>
using namespace std;
const int N = 1e5 + 100;
struct node {
int max;
int min;
}tree[N<<2];
int tmax, tmin;
void build(int l, int r, int top) {
if (l == r) {
cin >> tree[top].min;
tree[top].max = tree[top].min ;
return;
}
int mid = (l + r) / 2;
build(l, mid, top << 1);
build(mid + 1, r, top << 1 | 1);
tree[top].max = (tree[top << 1].max > tree[top << 1 | 1].max) ? tree[top << 1].max : tree[top << 1 | 1].max;
tree[top].min = (tree[top << 1].min < tree[top << 1 | 1].min) ? tree[top << 1].min : tree[top << 1 | 1].min;
}
void change(int l, int r, int top, int x,int y) {
if (l==x&&r==x) {
tree[top].max = tree[top].min = y;
return;
}
int mid = (l + r) / 2;
if (x <= mid) change(l, mid, top << 1, x, y);
else change(mid + 1, r, top << 1 | 1, x, y);
tree[top].max = (tree[top << 1].max > tree[top << 1 | 1].max) ? tree[top << 1].max : tree[top << 1 | 1].max;
tree[top].min = (tree[top << 1].min < tree[top << 1 | 1].min) ? tree[top << 1].min : tree[top << 1 | 1].min;
}
void solve(int l,int r,int top,int L,int R) {
if (l <= L && R <= r) {
if (tree[top].max > tmax) tmax = tree[top].max;
if (tree[top].min < tmin) tmin = tree[top].min;
return;
}
int mid = (L + R) / 2;
if (l <= mid) solve(l, r, top << 1, L, mid);
if (r > mid) solve(l, r, top << 1 | 1, mid + 1, R);
}
int main() {
int n, q;
cin >> n >> q;
build(1, n, 1);
while (q--) {
int sign,x,y;
cin >> sign >> x >> y;
if (sign == 1) {
change(1, n, 1, x, y);
}
else {
tmax = -1;
tmin = 0x3f3f3f3f;
solve(x, y, 1, 1, n);
if (tmax - tmin == y - x) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
}
}
E-使徒袭来
注意结果可以是小数,并不是一定时整数,当和一定时三个数相乘最大值的情况:三个数相同,所以反过来想当乘积一定时,和最小的情况下还是三个数相同的情况
ac代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
ios::sync_with_stdio(false);
double n;
scanf("%lf",&n);
double ans = pow(n,1.0/3);
printf("%.3lf\n",ans*3);
}
F-核弹剑仙
以前做过一道有点类似的题,是一道奶牛排名的题,记不太清楚了,我们将每个物件的强弱关系用有向图表示,如果a比b强,用bitset(一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间)类型的数组ans存结果,第i位是1表示第i件物件强于当前物件,所以ans[b]=ans[b]|ans[a],将直接比b强的和间接比b强的放在了一起。
ac代码
#include<iostream>
#include<bitset>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1010;
vector<int> adge[N];
int inadge[N];//入度
queue<int> que;
bitset<N> ans[N];
int n, m;
void solve() {
for (int i = 1; i <= n; i++) {//拓扑
if (inadge[i] == 0) {
que.push(i);
}
}
while (!que.empty()) {
int u = que.front();
que.pop();
for (int i = 0; i < adge[u].size(); i++) {
int v = adge[u][i];
inadge[v]--;
if (inadge[v] == 0) {
que.push(v);
}
ans[v] |= ans[u];
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
adge[x].push_back(y);
ans[y][x] = 1;
inadge[y]++;
}
solve();
for (int i = 1; i <= n; i++) {
cout << ans[i].count() << endl;
}
}
G-虚空之力
注意这里的字符是不需要连续也不需要有一定的·顺序的,我们直接统计需要的字符的个数,而且显然组成"kinging"的收益比组成"king"的收益比较高,所以我们要尽可能的组成"kinging"
ac代码
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
int m, ans = 0;
string str;
cin >> m >> str;
int k = 0, i = 0, n = 0, g = 0;
for (int q = 0; q < m; q++) {
if (str[q] == 'k') ++k;
else if (str[q] == 'i') ++i;
else if (str[q] == 'n') ++n;
else if (str[q] == 'g') ++g;
}
int ti = i / 2, tn = n / 2, tg = g / 2;
int sign = min(min(k, ti), min(tn, tg));
ans = sign * 2;
k -= sign;
i -= ans;
n -= ans;
g -= ans;
if (k && i && n && g) {
sign = min(min(k, i), min(n, g));
ans += sign;
}
cout << ans << endl;
}
H-社团游戏
明显的二维前缀和,然而比赛的后半段时间和别人瞎聊去了233,要注意的一点是需要二分
#include<iostream>
#include<bitset>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 510;
int map[30][N][N];
char str[N][N];
int n, m,k;
bool solve(int i,int j,int l,int r) {
for (int s = 0; s < 26; s++) {
int sign = map[s][l][r] - map[s][l][j - 1] - map[s][i - 1][r] + map[s][i - 1][j - 1];
if (sign > k) return false;
}
return true;
}
int main() {
cin >> n >> m>>k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> str[i][j];
}
}
for (int k = 0; k < 26; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
map[k][i][j] = map[k][i - 1][j] + map[k][i][j - 1] - map[k][i - 1][j - 1]+(k==str[i][j]-'a');
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int ans = 0;
for (int l = 1, r = min(n - i, m - j) + 1; l <= r;) {
int mid = (l + r) / 2;
if (solve(i, j, i + mid - 1, j + mid - 1)) {
ans = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
cout << ans <<" ";
}
cout << endl;
}
}
I-名作之壁
当l–r区间是满足条件的,那么l–r(r+1),l–(r+1),…,l–(n)都是满足的,所以我们的目标是对每个l找到这个r,我们维护好l–r的最大值和最小值即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<deque>
using namespace std;
typedef long long ll;
deque<ll> dqmin, dqmax;
const int N = 1e7 + 100;
const ll mod = 1e9;
ll arr[N];
int main() {
ios::sync_with_stdio(false);
int n, k, b, c,r = 1, l = 1;
scanf("%d %d %lld %d %d",&n,&k,&arr[0],&b,&c);
ll ans = 0;
for (; r <= n ;r++ ) {
arr[r] = (arr[r - 1] * b + c) % mod;
while (!dqmax.empty() && arr[dqmax.back()] <= arr[r]) dqmax.pop_back();//维护最大值
dqmax.push_back(r);
while (!dqmin.empty() && arr[dqmin.back()] >= arr[r]) dqmin.pop_back();//维护最小值
dqmin.push_back(r);
while (!dqmax.empty() && !dqmin.empty() && arr[dqmax.front()] - arr[dqmin.front()] > k) {
ans += n - r + 1;
l++;
if (!dqmax.empty() && dqmax.front() < l) dqmax.pop_front();
if (!dqmin.empty() && dqmin.front() < l) dqmin.pop_front();
}
}
printf("%lld\n",ans);
}
J-逃跑路线
ans=x&(21-1)&(22-1)&…&(2n-1),(21-1)&(22-1)&…&(2n-1)=1&11&111&1111&…=1,所以ans=x&1,a[i]范围显然要用到高精,不过太懒了用的java大数
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
BigInteger ans = BigInteger.ZERO;
for(int i=1;i<=n;i++){
BigInteger temp = scanner.nextBigInteger();
ans=ans.add(temp);
}
BigInteger mod = new BigInteger("10");
ans = ans.mod(mod);
int out = ans.intValue();
System.out.println(out&1);
}
}