首页 > 其他分享 >AtCoder Beginner Contest 258 A~Ex 题解

AtCoder Beginner Contest 258 A~Ex 题解

时间:2024-09-08 23:15:05浏览次数:11  
标签:10 le Beginner AtCoder int 题解 long maxn loop

D - Trophy

题目大意

有一个游戏,由\(N\)个关卡组成。第\(i\)个关卡由一个数对\((A_i,B_i)\)组成。

要通过一个关卡,你必须先花\(A_i\)的时间看一次介绍。然后,用\(B_i\)的时间打通这个关卡。若想多次通过同一个关卡,则第一次需要看介绍,后面无需再看(即如果想打通第\(i\)关\(N\)次,则所需时间为\(A_i+N\times B_i\))。

开始时,只有第一关被解锁。当你每打通一关,其下一关会自动解锁(最后一关除外)。求总共打通\(X\)关的最少时间(重复通关也算)。

\(1\le N\le 2\times 10^5\)
\(1\le A_i,B_i\le 10^9\)
\(1\le X\le N\)

输入格式

\(N~X\)
\(A_1~B_1\)
\(\vdots\)
\(A_N~B_N\)

输出格式

输出答案。

样例

略,请自行前往AtCoder查看。

分析

仔细想想会发现,通过的方式都是先不重复通过某一关前所有关卡,再通过这一关一定次数,最终达到正好\(X\)次。因此,我们利用前缀和,依次枚举每个关卡,最终时间复杂度可达\(\mathcal O(n)\)。

代码

#include <cstdio>
#define INF 0x7FFFFFFFFFFFFFFFLL
using namespace std;

int main()
{
	int n, x;
	scanf("%d%d", &n, &x);
	if(x < n) n = x;
	long long s = 0LL, ans = INF, cur;
	for(int i=1; i<=n; i++)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		if((cur = (s += a + b) + (long long)(x - i) * b) < ans)
			ans = cur;
	}
	printf("%lld\n", ans);
	return 0;
}

E - Packing Potatoes

题目大意

\(10^{100}\)个土豆排成一列。它们的重量分别是\(W_0,W_1,\dots,W_{N-1},W_0,\dots\),即第\(i\)个土豆的重量是\(W_{i\bmod N}\)(\(i=0,1,2,\dots\))。

Takahashi会往一个盒子里依次放入每个土豆,当放入的土豆总重量\(~\ge X\)的时候他会换一个新盒子。

给定\(Q\)个询问。第\(i\)个询问:给定整数\(K_i\),求第\(K_i\)个盒子中土豆的个数

\(1\le N,Q\le 2\times 10^5\)
\(1\le X,W_i\le 10^9\)
\(1\le K_i\le 10^{12}\)

输入格式

\(N~Q~X\)
\(W_0~\dots~W_{N-1}\)
\(K_1\)
\(\vdots\)
\(K_Q\)

输出格式

输出\(Q\)行,第\(i\)行是第\(i\)个询问的答案。

样例

略,请自行前往AtCoder查看。

分析

周期问题。

代码

#include <cstdio>
#include <vector>
#define maxn 200005
using namespace std;

using LL = long long;
int cnt[maxn], ord[maxn], w[maxn << 1];

template <typename T>
inline T read()
{
	char c;
	while((c = getchar()) < '0' || c > '9');
	T res = c ^ 48;
	while((c = getchar()) >= '0' && c <= '9')
		res = (res << T(3)) + (res << T(1)) + (c ^ 48);
	return res;
}

inline void print(int x)
{
	if(x > 9) print(x / 10);
	putchar(x % 10 ^ 48);
}

inline void println(int x)
{
	print(x);
	putchar('\n');
}

int main()
{
	int n = read<int>(), q = read<int>(), x = read<int>();
	LL sum = 0LL;
	for(int i=0; i<n; i++)
		sum += w[i + n] = w[i] = read<int>();
	int fill = x / sum * n;
	for(int i=0; i<n; i++)
		cnt[i] = fill, ord[i] = -1;
	x %= sum;
	for(int i=0, j=0, s=0; i<n; i++)
	{
		if(j < i) j = i, s = 0;
		while(s < x)
		{
			s += w[j];
			j += 1;
		}
		cnt[i] += j - i;
		s -= w[i];
	}
	vector<int> path;
	int loop = -1;
	for(int u=0, k=0; ; k++)
	{
		if(ord[u] != -1)
		{
			loop = k - ord[u];
			break;
		}
		ord[u] = k;
		path.push_back(u);
		(u += cnt[u]) %= n;
	}
	int non_loop = path.size() - loop;
	while(q--)
	{
		LL k = read<LL>();
		println(cnt[path[--k < non_loop? k:
				non_loop + (k - non_loop) % loop]]);
	}
	return 0;
}

F - Main Street

WJ...


G - Triangle

题目大意

给定一张由\(N\)个点组成的简单无向图\(G\)和它的邻接矩阵\(A\)。

什么是邻接矩阵

  • 邻接矩阵,顾名思义,即表示图中每两点之间关系的矩阵。
  • 如本题中\(A_{i,j}\)表示\(i,j\)两点之间是否有边。\(A_{i,j}=0\)表示无边,\(1\)表示有边。
  • 一般来说,对于任意简单无向图,\(A_{i,i}=0\),\(A_{i,j}=A_{j,i}\) (\(i\ne j\))。

求数对\((i,j,k)\)的个数,使得:

  • \(1\le i<j<k\le N\)
  • \((i,j,k)\)三个点在图中组成一个三角形,即\(i,j,k\)中任意两点之间有一条连边。

\(3\le N\le 3000\)

输入格式

\(N\)
\(A_{1,1}A_{1,2}\dots A_{1,N}\)
\(A_{2,1}A_{2,2}\dots A_{2,N}\)
\(\vdots\)
\(A_{N,1}A_{N,2}\dots A_{N,N}\)(注意没有空格,如10110

输出格式

输出一个整数,即符合条件的数对\((i,j,k)\)的个数。

样例

略,请自行前往AtCoder查看。

分析

前言

  • 个人感觉这题其实是这场比赛中最有意思的题。题目不难,但很具有研究意义。
    这里我将从各个角度分析题目,也期待大家在评论区中分享其他方法。

废话不多说,题解开始!

题目说得太啰嗦,其实不用管什么图论,可以看成是给定\(N\times N\)的\(01\)矩阵\(A\),求\(A_{i,j}=A_{i,k}=A_{j,k}=1\)的\((i,j,k)\)的个数。

再来看数据范围。\(N\le 3000\),则\(\mathcal O(N^3)\)的朴素算法时间可达到\(T(2.7\times 10^{10})\),显然无法通过。

然而,事实并非如此。
在仔细研究后发现,时间限制为\(3\mathrm{s}\)的题目可以使用复杂度稍高的算法。
但是一般来说,极端情况下超过\(T(10^{10})\)的算法无法通过。
因此,也许是数据不够强吧,使用如下的优化可以恰好通过(#32949139 \(37764\mathrm{KB},2755 \mathrm{ms}\)):

#pragma GCC optimize("Ofast") // -Ofast 预编译优化
#include <cstdio>
#define maxn 3000 // 数组大小设置正好,减少内存占用
using namespace std;

// 题目中正常的邻接矩阵
bool a[maxn][maxn];

// 特殊邻接表存储,减少尝试次数
// 这里不使用vector,会拖慢速度
int G[maxn][maxn], sz[maxn];

inline void print(const long long& x) // 快写-输出优化
{
	if(x > 9LL) print(x / 10);
	putchar(x % 10 ^ 48);
}

int main()
{
	// getchar快读输入优化
	int n = 0; char c;
	while((c = getchar()) != '\n')
		n = (n << 3) + (n << 1) + (c ^ 48);
	for(int i=0; i<n; i++, getchar())
		for(int j=0; j<n; j++)
			if(getchar() == '1' && j > i) // j > i:只存一半,去掉重复
				a[i][j] = 1, G[i][sz[i]++] = j;

	// 注意答案数据类型使用long long
	long long ans = 0LL;
	for(int v=0; v<n; ++v)
		for(int i=0; i<sz[v]; ++i) // 直接调取邻接表,省去不必要判断
		{
			int u = G[v][i];
			for(int j=0; j<sz[u]; ++j)
				if(a[v][G[u][j]])
					ans ++;
		}
	print(ans);
	return 0;
}

当然,这种方法并非每道题都能用,因此还是建议大家继续看正解。

正解还是基于上面的朴素算法,可看作:

  • 依次遍历\(A_{i,j}=1\)的\((i,j)\)(\(i<j\))
  • => 将答案加上\(A[i]\)和\(A[j]\)对应位置上都是\(1\)的位置个数
  • 输出答案,除以3(去掉每个重复算的三次)

那么别的地方都没办法,只有第二步可以使用bitset并集(&)操作进行优化。此时时间复杂度为\(\mathcal O(\frac{n^3}w)\),其中\(w=64\)。详见代码。

代码

#include <cstdio>
#include <bitset>
#define maxn 3000
using namespace std;

bitset<maxn> a[maxn];

int main()
{
	int n = 0; char c;
	while((c = getchar()) != '\n')
		n = (n << 3) + (n << 1) + (c ^ 48);
	for(int i=0; i<n; i++, getchar())
		for(int j=0; j<n; j++)
			if(getchar() == '1')
				a[i].set(j); // a[i][j] = 1
	long long ans = 0LL;
	for(int i=0; i+1<n; i++)
		for(int j=i+1; j<n; j++)
			if(a[i][j])
				ans += (a[i] & a[j]).count(); // 取交集,数1的个数
	printf("%lld\n", ans / 3LL);
	return 0;
}

标签:10,le,Beginner,AtCoder,int,题解,long,maxn,loop
From: https://www.cnblogs.com/stanleys/p/18403686/abc258

相关文章

  • AtCoder Beginner Contest 260 A~F 题解
    A-AUniqueLetter题目大意给定一个长度为\(3\)的字符串\(S\)。输出\(S\)中出现正好一次的字母(任意,如abc中,三个字母都可为答案)。如果没有,输出-1。数据保证\(S\)的长为\(3\),且由小写英文字母组成。输入格式\(S\)输出格式输出任意符合条件的答案。样例\(S\)输出......
  • LINE Verda Programming Contest (AtCoder Beginner Contest 263) A~E 题解
    A-FullHouse题目大意来自一个掼蛋爱好者的翻译qwq给定一副扑克牌中五张牌的编号\(A,B,C,D,E\),判断这五张是否为一组“三带二”。(不懂的自行百度数据范围:\(1\leA,B,C,D,E\le13\),且\(A,B,C,D,E\)不会全部相同。输入格式\(A~B~C~D~E\)输出格式如果是“三带二”,输出Yes;否......
  • BZOJ 1396 识别子串 题解
    Statement给\(S\),令\(x\)为\(S\)的第\(k\)个字符,称\(T=S[i..j]\)为关于\(x\)的识别子串,当且仅当:\(i\lek\lej\)(含\(x\)这一位)\(T\)在\(S\)中只出现一次求\(S\)关于每一位字符的最短识别子串长度,\(|S|\le10^5\).Solution1以下是我没看题解瞎胡的首先......
  • 动态规划01背包的一个例题——洛谷P2871 题解
    题面有N件物品和一个容量为M的背包。第I件物品的重量是W[i],价值是D[i].求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。样例数据输入46142631227输出23分析(如果亲爱的读者对动态规划略有了解的话应该能看出来这是个01背包的板子......
  • BZOJ 3796 Mushroom追妹纸 题解
    Statement给\(s_1,s_2,s_3\),求最长的\(w\)的长度,满足\(w\)是\(s_1\)子串\(w\)是\(s_2\)子串\(s_3\)不是\(w\)子串Solution1以下是我没看题解瞎胡的首先一个弱智想法是,枚举\(s_1\)上\(w\)的左端点,二分右端点,判定时\(s_2\)用SAM,\(s_3\)用单串AC自动......
  • BZOJ 4502 串 题解
    妙妙数数题key:数数题通常是,对于特定形式的计数,就盯着这个模式观察,看出一些充要条件、计数形式的转化,然后想办法维护。优化的本质就是把难算的变成好算的,把不好一起统计的(只能一个个数的)以某种角度、用某些数据结构,一起统计(多个多个数)。我觉得难点通常在于“盯出一些充要条件”,......
  • 题解:AT_arc116_b [ARC116B] Products of Min-Max
    在题库里面乱翻,就翻到了。因为在这道题里面子序列不需要考虑元素顺序,所以原序列无论是什么顺序都不会影响答案。所以先把元素按照从大到小的顺序排列,然后考虑每个元素的贡献。在当前序列中,对于元素\(a_i\),不妨设其为最小值,并去寻找它能作为哪些序列的最小值。容易发现它作为最......
  • 题解:AT_abc369_c [ABC369C] Count Arithmetic Subarrays
    很水的一道题,但是硬控我半个小时呜呜呜。它问等差数列的数量,我们发现只要找到所有的等差数列,那么答案一定包含在这些数列的连续子序列中。求所有等差数列显然可以线性,我们求出每个等差数列的长度\(n\),那么连续子序列个数即为\(n(n+1)\over2\)。至于求的话我定义了两个指针,每......
  • AtCoder Beginner Contest 253 A~E 题解
    A-Median?题目大意给定正整数\(a,b,c\),判断\(b\)是否为三个数中的中位数(即从小到大排序后是第二个,不是平均数)。\(1\lea,b,c\le100\)输入格式\(a~b~c\)输出格式如果\(b\)是三个数中的中位数,输出Yes;否则,输出No。样例\(a\)\(b\)\(c\)输出\(5\)\(3\)\(2\)Y......
  • AtCoder Beginner Contest 241 (Sponsored by Panasonic) D~F 题解
    D-SequenceQuery题目大意我们有一个空序列\(A\)。请依次处理\(Q\)个命令,每个命令有三种类型,每种类型的格式如下:1x:将\(x\)加入\(A\)(不去重)2xk:求在\(A\)的\(\lex\)的元素中,第\(k\)大的值。3xk:求在\(A\)的\(\gex\)的元素中,第\(k\)小的值。\(1\leQ\le2\times10^5......