首页 > 其他分享 >牛客多校2

牛客多校2

时间:2023-07-22 18:22:45浏览次数:31  
标签:const fu val int 多校 long 牛客 ret

D.The Game of Eating

题意:

有\(n\)个人,\(m\)种菜,从\(1\)开始轮流点菜,一共点\(k\)道,\(n\)点完轮到\(1\),直到点完,点过的菜其他人不能再点。第\(i\)个人对第\(j\)道菜有\(A_{i,j}\)的喜好度,每个人都想让自己对所有已选的菜的喜好度总和最大,他们能彼此看到对菜的喜好度,问最后点了的菜有什么?

思路:

假设第一个人有一道菜是他喜欢的菜里面最大的,这道菜也是别人菜里面最大的,那么他肯定不选这个,选一个次大的。这样,我们不仿从第\(k\)个人开始选,这样前面的人的最大就会被选走了,倒序模拟一遍即可。

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 2e3 + 5, M = 2e3 + 5, inf = 0x3fffffff;
const long long INF = 0x3fffffffffffffff, mod = 998244353;

int main() {
    ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;

	while(t--) {
		int n, m, k;
		cin >> n >> m >> k;
		vector<vector<int>> a(n + 1, vector<int>(m + 1));
		vector<priority_queue<pair<int, int>>> q(n + 1);
		vector<bool> c(m + 1);
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= m; j++) {
				cin >> a[i][j];
				q[i].emplace(a[i][j], j);
			}
		}

		int now = (k - 1) % n + 1;
		vector<int> ans;
		for(int i = 1; i <= k; i++) {
			while(c[q[now].top().second]) q[now].pop();
			ans.emplace_back(q[now].top().second);
			c[q[now].top().second] = true;
			now--;
			if(now == 0) {
				now = n;
			}
		}

		sort(ans.begin(), ans.end());
		for(int i = 0; i < ans.size(); i++) {
			cout << ans[i] << " \n"[i + 1 == ans.size()];
		}
	}

    return 0;
}

E.Square

题意:

给出一个\(x(1\leq x\leq10^9)\),在\(x\)的数位后拼接数字,使得他存在一个\(y\)满足\(0\leq y\leq 10^9\)且\(y^2=x\)

思路:

由于\(y\)的范围,这就限定了\(x\leq10^{18}\),这样我们只需要枚举拼接的数位个数即可,假设\(x=123\),拼接了四位,那么结果的范围就是\([1230000, 1239999]\),可能的\(y\)就在\([\sqrt{1230000}, \sqrt{1239999}]\)对这一部分二分,二分数的检查头\(3\)位即可,\(x\)有多少位就检查多少位即可。

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 2e5 + 5, M = 2e5 + 5, inf = 0x3fffffff;
const long long INF = 0x3fffffffffffffff, mod = 998244353;

using mint = ll;

mint cal(int x, int y) {
	mint ret = 1;
	for(int i = 1; i <= y; i++) {
		ret *= x;
	}
	return ret;
}

mint geth(int len) {
	mint ret = 0;
	while(len--) {
		ret = ret * 10 + 9;
	}
	return ret;
}

void work() {
	mint x;
	cin >> x;

	if(x == 0) {
		cout << 0 << "\n";
		return;
	}

	int d = (int)log10(x) + 1;
	for(int i = 0; i <= 19 - d; i++) {
		
		mint b = cal(10, i);
		if(x > (mint)1e18 / b) {
			break;
		}
		mint l = x * b, r = l == (mint)1e18 ? l : l + geth(i);
		mint lsq = ceil(sqrt(l)), rsq = (int)sqrt(r);

		while(lsq <= rsq) {
			mint mid = (lsq + rsq) / 2;
			mint v = mid * mid;

			while((int)log10(v) + 1 > d) {
				v /= 10;
			}

			if(v == x) {
				cout << mid << "\n";
				return;
			}

			if(v > x) {
				rsq = mid - 1;
			} else {
				lsq = mid + 1;
			}
		}
	}

	cout << -1 << "\n";
}

int main() {
    ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;

	while(t--) {
		work();
	}

    return 0;
}

题意:

字符\(s,o,x,z\)是自我中心对称的,字符\(\{u, n \},\{q, b\},\{d,p\}\)是对应中心对称的。给出一个字符串, 确定是否是由若干个中心对称的串首尾拼接起来的。

思路:

从头找,每找到一个中心对称串,就把他删去,这样操作下去,可以删空原串就是符合题意的。

判断是否是中心对称串可以把字符看成对应对称字符,然后就是求回文串,可以用哈希解决,也可以用manacher算法

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 2e6 + 5, M = 2e5 + 5, inf = 0x3fffffff;
const long long INF = 0x3fffffffffffffff, mod = 998244353;

string strs = "bqdpunosxz#";
string strt = "qbpdnuosxz#";
map<char, char> inv;
set<char> set1;

string trans(const string &s) {
	string ret;
	ret += '#';
	for(char c : s) {
		ret += c;
		ret += '#';
	}
	return ret;
}

string s;
int p[N];

void work() {
	cin >> s;

	for(char c : s) {
		if(!set1.count(c)) {
			cout << "NO" << "\n";
			return;
		}
	}

	s = " " + trans(s);

	int mid = 0, mr = 0, l = 1, n = (int)s.size() - 1;
    for(int i = 1; i <= n; i++) {
        p[i] = mr >= i ? min(mr - i + 1, p[2 * mid - i]) : s[i] == inv[s[i]];
        while(s[i - p[i]] == inv[s[i + p[i]]]) p[i]++;
        if(l <= i && i - p[i] + 1 <= l) {
            l = 2 * i - l + 1;
        }
        if(i + p[i] - 1 > mr) {
            mr = i + p[i] - 1;
            mid = i;
        }
    }

	if(l == n + 1) cout << "YES" << "\n";
	else cout << "NO" << "\n";
}

int main() {
    ios::sync_with_stdio(false);
	cin.tie(nullptr);

	for(int i = 0; i < strs.size(); i++) {
		inv[strs[i]] = strt[i];
		inv[strt[i]] = strs[i];
		set1.emplace(strs[i]);
		set1.emplace(strt[i]);
	}

	int tt;
	cin >> tt;

	while(tt--) {
		work();
	}

    return 0;
}

H.0 and 1 in BIT

给定一个对二进制数的操作序列,其中\(A\)代表然这个二进制数取反,\(B\)代表让这个数\(+1\)

给出若干操作,每个操作给出\(L,R,X\),问对\(X\)顺序做\([L,R]\)的结果是什么?

取反操作可以看成补码的操作,有~x == -x - 1

这么一来只需要快速查询区间操作和,可以用倍增实现,也可以用前缀和

下面是一个前缀和的实现

#include<bits/stdc++.h>
using namespace std;

#define int long long

using ll = long long;

const int N = 1e6 + 5;

int n, q;
string s;

struct ele {
    int fu, val;
    ele operator+(const ele &x) const {
        ele ret;
        if(x.fu) {
            ret.fu = fu ^ x.fu;
            ret.val = -val + x.val;
        } else {
            ret.fu = fu;
            ret.val = val + x.val;
        }
        return ret;
    }
    
    ele operator-(const ele &x) const {
        ele ret;
        ret.fu = fu ^ x.fu;
        ret.val = val - (ret.fu ? -x.val : x.val);
        return ret;
    }
}sum[N];

signed main() {
    #ifdef stdjugde
        freopen("in.txt", "r", stdin);
    #endif

    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> q >> s;
    s = "?" + s;

    //ele(fu, value)
    for(int i = 1; i <= n; i++) {
        if(s[i] == 'A') sum[i] = sum[i - 1] + (ele){1, -1};
        else sum[i] = sum[i - 1] + (ele){0, 1};
    }

    auto trans = [&](int l, int r, ll ans) -> tuple<int, int> {
        int x = (ans ^ l) % n + 1ll;
        int y = (ans ^ r) % n + 1ll;
        return {min(x, y), max(x, y)};
    };

    auto _2to10 = [&](string str) -> ll {
        ll ret = 0;
        reverse(str.begin(), str.end());
        for(int i = 0; i < str.size(); i++) {
            if(str[i] == '1') {
                ret += 1ll << i;
            }
        }
        return ret;
    };

    auto _10to2 = [&](ll x, int len) {
        string ret;
        for(int i = 0; i < len; i++) {
            ret += '0' + (x & 1ll);
            x >>= 1ll;
        }
        reverse(ret.begin(), ret.end());
        return ret;
    };

    ll ans = 0;
    while(q--) {
        int l, r;
        cin >> l >> r;
        tie(l, r) = trans(l, r, ans);

        string str;
        cin >> str;

        ans = _2to10(str);
        
        ele res = sum[r] - sum[l - 1];

        if(res.fu) ans = -ans;
        ans += res.val;

        string anss = _10to2(ans, str.size());

        cout << anss << "\n";
        ans = _2to10(anss);
    }

    return 0;
}

K.Box

题意:

有\(n\)个盒子,一开始每个盒子上面可能有盖子,对于每个盖子可以将他左移一格或右移一格或原地不动,每个盒子有权值\(a_{i}\),有盖子的盒子可以获得其权值,问最多可以获得多少权值?

思路:

每个位置有\(4\)个状态:取左边位置的盖子,取当前位置的盖子,取后一个位置的盖子,没有盖子

每个盖子有\(3\)个状态:到左边去,原地不动,到右边去

对盖子dp是比较好实现的,因为有一个重要的性质:盖子的相对顺序不改变一定可以获得最优的结果

所以对于第\(i\)个盖子只需要放的比第\(i - 1\)个后就可以了

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 1e6 + 5, M = 2e5 + 5, inf = 0x3fffffff;
const long long INF = 0x3fffffffffffffff, mod = 998244353;

int n, a[N], b[N];
ll dp[N][3];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	vector<int> vec;
	for (int i = 1; i <= n; i++) {
		cin >> b[i];
		if(b[i]) vec.emplace_back(i);
	}

	for (int i = 0; i <= n; i++) {
		for (int j = 0; j < 3; j++) {
			dp[i][j] = -INF;
		}
	}

	if (vec[0] > 1) {
		dp[0][0] = a[vec[0] - 1];
	}
	dp[0][1] = a[vec[0]];
	if (vec[0] < n) {
		dp[0][2] = a[vec[0] + 1];
	}

	for (int i = 1; i < vec.size(); i++) {
		for (int j = 0; j < 3; j++) {
			if (1 <= vec[i] + j - 1 && vec[i] + j - 1 <= n) {
				for (int k = 0; k < min(vec[i] - vec[i - 1] + j, 3); k++) {
					if (1 <= vec[i - 1] + k - 1 && vec[i - 1] + k - 1 <= n) {
						dp[i][j] = max(dp[i][j], dp[i - 1][k] + a[vec[i] + j - 1]);
					}
				}
			}
		}
	}

	ll ans = 0;
	for (int i = 0; i < 3; i++) {
		ans = max(ans, dp[(int)vec.size() - 1][i]);
	}

	cout << ans << endl;
	return 0;
}

标签:const,fu,val,int,多校,long,牛客,ret
From: https://www.cnblogs.com/yawnsheep/p/17573830.html

相关文章

  • 暑假牛客多校第二场 2023-7-21
    未补完E.Square算法:二分做法:我们依据x来枚举k,得到\(x*10^k\),用二分在[0,1e9]查找mid的平方值,且这个值是第一个大于等于\(x*10^k\)的值。得到这个值后我们再判断这个值在除\(10^k\)后是否与\(x\)相等即可。code#include<iostream>#include<cstring>#incl......
  • 2023牛客多校7.21补题
    D-TheGameofEating题意:一共有m道菜,n个人轮流点一道菜,一共点k道。第i个人对第j道菜的喜爱程度\(A_{i,j}\)对所有人公开,一个人点了菜所有人都可以吃到。每个人都希望最大化自己的喜爱程度之和,求最终的点菜集合。分析:很容易想到每个人点菜时都点当前剩下的菜中自己最喜爱的,但是......
  • 牛客暑假多校 2023 第二场
    写在前面比赛地址:https://ac.nowcoder.com/acm/contest/57356。我是MINUS-FIFTEEN级超级战犯。澄清一下,我不是声优厨,我不是声优厨,我不是声优厨。同样是题目选补,我是飞舞。以下个人向难度排序。I签到。随便手玩一下就行。D虽然每个人都倾向于吃到自己最喜欢的菜,但给在......
  • 2023 牛客暑期多校
    7.17我正开,Dgjk倒开,AHJKLMA-AlmostCorrect设\(s\)中\(0\)的下标集合为\(S_{0}\),\(1\)的为\(S_{1}\),最右边的\(0\)的下标\(r\),最左边\(1\)的下标\(l\)。\(s\)没有排好序所以\(l\le|S_{1}|<r\)\(\foralli\inS_{0},(i,r)\)\(\foralli\inS_{1},(l......
  • 2023牛客多校2
    H.0and1inBIT题意给一串操作字符串,其中包含操作\(A,B\):\(A\)代表将二进制每一位反转。\(B\)代表将二进制加\(1\)。且当二进制为全\(1\)时,二进制变为全\(0\)现在包含多次询问,每次询问给定一个区间(区间需要计算得到),给定一个初始二进制\(x\),问你二进制在经过操作字符串对......
  • 2023 暑假牛客多校
    时隔一年,多校又至。还是和jimmywang与shihoghmean组队。只可惜后面要文化课了,可能打不完。只记一些赛时想过的和听完题解后会的妙妙题:7.17“范式杯”2023牛客暑期多校训练营1......
  • “范式杯”2023牛客暑期多校训练营1
    D:Chocolate大意:给定一个n*m的方格,上面摆放着巧克力,k和w在玩一个游戏,规定k先行,在每个回合内玩家可以吃掉坐标(x,y)内所有的巧克力(i<=x&&j<=y),在他们回合内至少吃掉一块巧克力,谁最后吃巧克力谁就输了,问赢家是谁做法:一个很经典的博弈论,chomp游戏,这个游戏经过证明可以得到先手必赢,......
  • 2023杭电多校第二场
    目录1009StringProblem比赛地址:传送门这回过了三个题,后面4个小时都在坐牢~1009StringProblem题意:给你一个字符串,让你找成对不相交的子串,每个子串仅由一个字符组成,其对于答案的贡献为子串长度-1,问你最大化贡献。思路:就是判断是否有相邻位均为同一字符串,如果则++ans......
  • 2023杭电多校第二场
    1001求个SG然后打表发现$SG=0$的点满足$t=k_1*(4*K+2)+(K+1)$#include<bits/stdc++.h>usingnamespacestd;intT,N;intmain(){cin>>T;while(T--){intN,K;cin>>K>>N;if(N<=K)cout<<&......
  • 2023牛客多校7.17补题
    当时就做了两道签到题DJ,这两天补了四道简单题HKLMD-Chocolate题意:\(n×m\)的巧克力,Kelin先手,WalkAlone后手,每人每次拿走一块左下角为\((1,1)\)的子矩形的巧克力,谁拿走\((n,m)\)处的巧克力谁输。分析:这是一道结论题,只有\(1×1\)的时候后手赢,其余情况下都是先手赢。证明......