2021南宁周赛!第一期题解

前话:全是签到题!(除了最后一题

本题解秉承遇事不决放标程代码的良好作风,旨在让各位了解题目的简单性与我们的善良。
补题入口

更新:
H 数据背锅了,最后一个数据出现了重复边,并且当时出题人没考虑到重边问题没加min取最小值,而造数据的手贱暴力造了一组大数据,然后就出了大问题。对于Floyd的问题我再次表示郑重道歉。

A 题数据弱了,出题人数据刚好没有造出来一组卡算法的数据,因此对于 o ( n ) o(n) on算法的选手应该都是错的。

C 题验题人把关不够严,大家看到背包问题就直接读数据了,没有注意到题面描述有问题。在此第二次道歉。

B 题原题-传送门hjm想摸鱼

I 题原题传送门小西卷师

A题原题hjm的卡牌游戏


A: hjm 的卡牌游戏

本题算是思维题+观察数据,普通的寻找卡牌最大值肯定不行,或许可以用线段树或者优先队列过。标程给出的是暴力枚举最大值。

因为数据关系,因此最大值有且只有六十种可能,那么对于每种可能我们都进行一次数组清算。根据尺取原则,定义贡献值为从上一个位置到当前位置一共增加的积分,若积分为负,则为负贡献,那就舍去。记录下所有正贡献情况。

时间复杂度就成了 o ( 30 ∗ n ) o(30*n) o30n

#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。

祝各位下周比赛签到同样愉快!

猜你喜欢

转载自blog.csdn.net/Crescent521/article/details/115253401
今日推荐