前话:全是签到题!(除了最后一题
本题解秉承遇事不决放标程代码的良好作风,旨在让各位了解题目的简单性与我们的善良。
补题入口
更新:
H 数据背锅了,最后一个数据出现了重复边,并且当时出题人没考虑到重边问题没加min取最小值,而造数据的手贱暴力造了一组大数据,然后就出了大问题。对于Floyd的问题我再次表示郑重道歉。
A 题数据弱了,出题人数据刚好没有造出来一组卡算法的数据,因此对于 o ( n ) o(n) o(n)算法的选手应该都是错的。
C 题验题人把关不够严,大家看到背包问题就直接读数据了,没有注意到题面描述有问题。在此第二次道歉。
B 题原题-传送门hjm想摸鱼
I 题原题传送门小西卷师
A题原题hjm的卡牌游戏
A: hjm 的卡牌游戏
本题算是思维题+观察数据,普通的寻找卡牌最大值肯定不行,或许可以用线段树或者优先队列过。标程给出的是暴力枚举最大值。
因为数据关系,因此最大值有且只有六十种可能,那么对于每种可能我们都进行一次数组清算。根据尺取原则,定义贡献值为从上一个位置到当前位置一共增加的积分,若积分为负,则为负贡献,那就舍去。记录下所有正贡献情况。
时间复杂度就成了 o ( 30 ∗ n ) o(30*n) o(30∗n)。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, a[N], ans;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int mx = 0; mx <= 30; mx++) {
int sum = 0;
for (int rt = 1; rt <= n; rt++) {
sum += a[rt];
if (a[rt] > mx)
sum = 0;
if (sum < 0)
sum = 0;
ans = max(ans, sum - mx);
}
}
cout << ans << endl;
return 0;
}
B:hjm学姐想要摸鱼
数据弱,看起来好像很难,其实就是一个简单的暴力扫图。
这题改编自一道洛谷博弈论,改了一下胜负条件,就变成了暴力扫图题。
简单来说,我们可以在sort之后观察到所谓的上取走一个堆,或者抓走每一个,其实都是在走一张图。
因此我把数据转化成图,根据博弈结果,碰到边界的人赢。从后往前推,如果当遇到博弈下面两条路结果为必胜点,就转化为必败点,不断翻转,一直推到初始点即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
unsigned long long x;
int n, a[25], b[25], M[25][25];
int main() {
cin>>n;
for(int i=1; i<=n; i++) {
cin>>a[i];
}
sort(a+1, a+1+n, greater<int>());
for(int i=1; i<=n; i++) {
M[a[i]][i]=1;
int now=a[i];
while(now!=a[i+1]) {
M[now--][i]=1;
}
}
for(int j=n-1; j>=1; j--) {
for(int i=a[j]-1; i>=1; i--) {
if(M[i+1][j]==1&&M[i][j+1]==1) {
M[i][j]=0;
}
else
M[i][j]=1;
}
}
if(M[1][1]) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
C: jmr的仁慈
板子题:二维多重背包,不会的自己面壁,好好反思DP为什么背包题都签不了。
#include<iostream>
#include<random>
using namespace std;
int x[5000][5];
int dp[5000][5000];
//std::mt19937 rng;
//rng.seed(std::random_device()());
//std::uniform_int_distribution<std::mt19937::result_type> dist(1, 10);
int main() {
long long n, m, q;
cin >> n >> m >> q;
// n = dist(rng);
for (int i = 0; i < n; i++) {
cin >> x[i][1] >> x[i][2];
}
for (int i = 0; i < n; i++) {
for (int j = x[i][1]; j <= m; j++) {
for (int k = x[i][2]; k <= q; k++) {
dp[j][k] = max(dp[j][k], dp[j - x[i][1]][k - x[i][2]] + 1);
}
}
}
cout << dp[m][q] << endl;
}
D: peach 想开邮轮
题面讲的有点烂,我大概给大家翻译一下:如果有人的邮轮生疏度比较大,那么让他带着peach,反正不用坐满人,多让生疏度大多拉几次。那么就变成了贪心题了。
最后一个恶意:数据范围是0开始的,所以存在有人可以直接拉走peach。还不如peach自己开。
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a,int b) {
return a > b;
}
int main() {
int a, b;
int x[1000]={
};
cin >> a >> b;
for (int i = 0; i < b; i++) {
cin >> x[i];
}
int ans = 0;
sort(x, x + b,cmp);
for (int i = 0; i < a; i++) {
if(x[i]>1)ans+=x[i];
else ans+=1;
}
cout << ans;
}
E: Peach 想开邮轮之白嫖篇
经典dfs了,你在dfs的过程中加一个油量指标,回溯点总不用我再强调了吧。这题也是为了照顾算法薄弱的选手,多补补dfs的类型题。
(不记忆化搜索应该也可以过,数据这么弱,就是一道签到题定义的)
#include <iostream>
#include<queue>
//#include<bits/stdc++.h>
using namespace std;
const int maxn = 50;
char a[maxn][maxn];///地图字符串数组
int X[4] = {
1,-1,0,0 }, Y[4] = {
0,0,1,-1 };///增量数组
int visit[maxn][maxn] = {
0 };
int vis[maxn][maxn] = {
0 };
///记录数组,记得最后要清0,记录节点是否已经入队,提升程序效率;
int n, m;
const int inf = 0x3f3f3f;
int ans = inf;
typedef struct node
{
int x, y, step;
int you;
}T1;
T1 S, T;
bool check(int x, int y,int r)///检测函数
{
if (x < 1 || y < 1 || x > n || y > m) return false;///越界
if ( a[x][y] == '0') return false;///访问过了或不可移动
if (visit[x][y] && vis[x][y] > r)return false;
if (r <= 0)return false;
return true;
}
void dfs(T1 W) {
if (!check(W.x, W.y, W.you)) {
return;
}
if (W.x == T.x && W.y == T.y) {
ans = min(ans, W.step);
return;
}
if (W.step > ans)return;
if (a[W.x][W.y] == '4')W.you = 6;
for (int i = 0; i < 4; i++) {
visit[W.x][W.y] = 1;
vis[W.x][W.y] = W.you;
T1 tmp = W;
tmp.step++;
tmp.x += X[i];
tmp.y += Y[i];
tmp.you--;
dfs(tmp);
visit[W.x][W.y] = 0;
vis[W.x][W.y] = 0;
}
}
int main()
{
{
cin >> n >> m;
int i, j;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
cin >> a[i][j];
if (a[i][j] == '2') {
S.x = i, S.y = j; }
if (a[i][j] == '3') {
T.x = i, T.y = j; }
}
a[i][j + 1] = '\0';
}
S.you = 6;
S.step = 0;
dfs(S);
if (ans == inf)cout << -1 << endl;
else
cout << ans << endl;
}
return 0;
}
F:sct学妹想要划水
博弈论,科普一下:这题算是思维型的,可以用sg值,但没必要,出题者想法是先手被堵就无法抓最后一个,因此想赢必须只能在第一次就赢。因此判定两堆是否存在1即可。
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main() {
long long a,b;
cin >> a >> b;
if (a == 1 || b == 1) {
cout << "Yes" << endl;
}
else cout << "No" << endl;
}
G: ZP的简单题
坑1,多组数据
坑2,c++ 刚好爆long long
坑3,哥德巴赫猜想:大于等于6都可以。
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
unsigned long long a;
while(cin >> a){
//int flag = 0;
if (a >= 6)cout << "Jiuzhe?" << endl;
else cout << "Grass" << endl;
}
}
H: 小金的猫城堡
暴力Floyd,对于每一条边都试试他是不是那个捷径,把所有的情况算出来找最小值。
前提得会Floyd哈,不会建议先自学一下。就是把所有边都提出来,和一个点连线看看是不是绕了这个点速度更快。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MAXN 105
int n, m;
int G[MAXN][MAXN];
LL ans = 0x3f3f3f3f3f3f3f3f;
void check(int a, int b) {
LL tot = 0;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
tot += min(G[i][j], min(G[i][a] + G[b][j], G[i][b] + G[a][j]));
}
}
ans = min(tot, ans);
}
int main() {
cin >> n >> m;
memset(G, 0x3f, sizeof G);
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
G[u][v] = G[v][u] = w;
}
for (int i = 1; i <= n; i++) G[i][i] = 0;
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (G[i][k] + G[k][j] < G[i][j])
G[i][j] = G[i][k] + G[k][j];
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++) {
check(i, j);
}
cout << ans << endl;
return 0;
}
I: 小西的卷师
线段树,多了一点点细节就过了。
数据一共就造了三组,没关系,wa,多wa几发就过了。
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define ll long long
#define mod 1000000007
ll val[2500005], nex[2500005], pre[2500005], siz[2500005], n, a[600005], pr[600005], oe[600005], b[600005], tot, mi[600005], inv2, m;
struct l1 {
ll x, v;
}q[600005];
ll add(ll x) {
return x >= mod ? x - mod : x; }
ll ksm(ll x, ll y) {
ll ans = 1, t = x;
while (y) {
if (y & 1) ans = ans * t % mod;
t = t * t % mod;
y >>= 1;
}
return ans;
}
void push_up(ll p) {
val[p] = (val[p * 2] + val[p * 2 + 1] + nex[p * 2] * pre[p * 2 + 1]) % mod;
nex[p] = (nex[p * 2 + 1] + nex[p * 2] * mi[siz[p * 2 + 1]]) % mod;
pre[p] = (pre[p * 2] + pre[p * 2 + 1] * mi[siz[p * 2]]) % mod;
siz[p] = siz[p * 2] + siz[p * 2 + 1];
}
void insert(ll p, ll l, ll r, ll sit, ll v) {
if (l == r) {
siz[p] += v;
val[p] = oe[siz[p]] * b[l] % mod * b[l] % mod;
pre[p] = nex[p] = pr[siz[p]] * b[l] % mod;
return;
}
ll mid = l + r >> 1;
if (sit <= mid) insert(p * 2, l, mid, sit, v);
else insert(p * 2 + 1, mid + 1, r, sit, v);
push_up(p);
}
int main() {
scanf("%lld", &n); inv2 = ksm(2, mod - 2); mi[0] = 1;
for (ll i = 1; i <= n; i++) mi[i] = mi[i - 1] * inv2 % mod;
for (ll i = 1; i <= n; i++) pr[i] = add(pr[i - 1] + mi[i]);
for (ll i = 2; i <= n; i++) oe[i] = (oe[i - 1] + pr[i] - pr[1] + mod) % mod;
for (ll i = 1; i <= n; i++) scanf("%lld", &a[i]), b[++tot] = a[i];
scanf("%lld", &m);
for (ll i = 1; i <= m; i++) {
scanf("%lld%lld", &q[i].x, &q[i].v);
b[++tot] = q[i].v;
}
sort(b + 1, b + tot + 1);
tot = unique(b + 1, b + tot + 1) - b - 1;
for (ll i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
for (ll i = 1; i <= m; i++) q[i].v = lower_bound(b + 1, b + tot + 1, q[i].v) - b;
for (ll i = 1; i <= n; i++) insert(1, 1, tot, a[i], 1);
printf("%lld\n", val[1]);
for (ll i = 1; i <= m; i++) {
insert(1, 1, tot, a[q[i].x], -1);
a[q[i].x] = q[i].v;
insert(1, 1, tot, a[q[i].x], 1);
printf("%lld\n", val[1]);
}
}
结语:
感谢出题人:1v3小队 hjm ,sct(peach),hy。
给个机会打银川队: zp,jmr,hzb。
祝各位下周比赛签到同样愉快!