「GMOI」Round 1

P8924 「GMOI R1-T1」Perfect Math Class

思路

  1. 因为 n n n m m m 均不超过 100 100 100,所以我们用 v i s [ i ] [ j ] vis[i][j] vis[i][j] 表示第 i i i 行第 j j j 列是否函数上。当然,用 map 去维护点的信息也可以。
  2. 用因为 k ≤ 7 k\le7 k7,故计算函数值 y y y 的时候要开 long long。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxk = 15;
map <pair <int, int>, int> vis; 
int n, m, k, a[maxk];
int main ()
{
	scanf ("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= k + 1; i++)
		scanf ("%d", &a[i - 1]);
	for (int x = 0; x <= n - 1; x ++) 
	{
		long long y = 0, p = 1;
		for (int i = 1; i <= k + 1; i++) 
		{
			y += p * a[i - 1];
			p *= x;
		}
		if (y < 0 || y > m - 1) continue;
		vis.insert (make_pair (make_pair (x, y), 1)); 
	}
	for (int i = m - 1; i >= 0; i--) 
	{
		for (int j = 0; j <= n - 1; j++) 
			if (vis.find (make_pair (j, i)) == vis.end ())
			printf (".");
			else printf ("*");
		printf ("\n");
	}
	return 0;
}

P8925 「GMOI R1-T2」Light

思路

  1. 我们设左边的第 n n n 项是 a n a_n an,右边第 n n n 项是 b n b_n bn。易得, a 1 = − 2 L a_1=-2L a1=2L b 1 = 2 R b_1=2R b1=2R
  2. 根据题意, a n + b n − 1 2 = − L \frac{a_n+b_{n-1}}{2}=-L 2an+bn1=L b n + a n − 1 2 = R \frac{b_n+a_{n-1}}{2}=R 2bn+an1=R。故易得, a n − a n − 2 = − 2 R − 2 L a_n-a_{n-2}=-2R-2L anan2=2R2L。分奇偶讨论,当 n n n 为奇数时, a n = − ( n + 1 ) L − ( n − 1 ) R a_n=-(n+1)L-(n-1)R an=(n+1)L(n1)R;当 n n n 为偶数时, a n = − n ( R + L ) a_n=-n(R+L) an=n(R+L) b n b_n bn 同理可得。

代码

#include <bits/stdc++.h>
using namespace std;
long long l, r, n, ans;
int T; 
int main ()
{
	scanf ("%d", &T);
	scanf ("%lld %lld", &l, &r);
	while (T --) 
	{
		char turn; 
		cin >> turn, scanf ("%lld", &n);
		if (turn == 'L') 
		{
			if (n & 1ll) ans = -(n + 1) * l - (n - 1) * r;
			else ans = -n * l - n * r;
		} 
		else 
		{
			if (n & 1ll) ans = (n + 1) * r + (n - 1) * l;
			else ans = n * r + n * l;
		}
		printf ("%lld\n", ans);
	}
	return 0;
}

P8926 「GMOI R1-T3」Number Pair

思路

  1. x = gcd ⁡ ( x , y ) x 1 x=\gcd(x,y)x_1 x=gcd(x,y)x1 y = gcd ⁡ ( x , y ) y 1 y=\gcd(x,y)y_1 y=gcd(x,y)y1,则易得 gcd ⁡ ( x 1 , y 1 ) = 1 \gcd(x_1,y_1)=1 gcd(x1,y1)=1。由 k gcd ⁡ ( x , y ) = lcm ⁡ ( x , y ) k\gcd(x,y)=\operatorname{lcm}(x,y) kgcd(x,y)=lcm(x,y) 得, k gcd ⁡ ( x , y ) 2 = x y k{\gcd(x,y)}^2=xy kgcd(x,y)2=xy,进而 k = x 1 y 1 k=x_1y_1 k=x1y1,故欲求满足条件的 ( x , y ) (x,y) (x,y) 的对数,我们需要找到 k k k 分解成两个互质的数相乘的方案数
  2. 根据唯一分解定理把 k k k 分解成 p 1 r 1 p 2 r 2 ⋯ p n r n p_1^{r_1}p_2^{r_2}\cdots p_n^{r^n} p1r1p2r2pnrn。若 p i ∣ x 1 p_i \mid x_1 pix1,则 p i ∤ y 1 p_i \nmid y_1 piy1。故可知, k k k 分解成两个互质的数相乘的方案数是 2 n 2^n 2n,可由快速幂得到。
  3. 如何得到 k k k 的标准分解式。因为 p i , i ∈ { 1 , 2 … n } p_i,i\in \{1,2\dots n\} pi,i{1,2n}至多有一个大于 k \sqrt{k} k 的素数,所以我们可以先通过线性筛得到 1 1 1 1 0 8 10^8 108 内所有的素数。因为 1 1 1 1 0 8 10^8 108 中只有 28724216 28724216 28724216 个素数,故我们要卡着这个值开数组,避免MLE。我们将 n n n 初始化为 0 0 0,然后枚举这些素数,如果某个素数可以整除 k k k,那么 n + 1 n + 1 n+1,并不断用这个素数除 k k k 直到这个素数 ∤ k \nmid k k。若退出循环后 k ≠ 1 k\ne1 k=1,则说明 k k k 的标准分解式中有一个大于 k \sqrt{k} k 的素数,那么 n + 1 n+1 n+1
  4. 因为 P ≤ gcd ⁡ ( x , y ) ≤ Q P\leq \gcd(x,y)\leq Q Pgcd(x,y)Q,所以最后的答案就是 ( Q − P + 1 ) 2 n (Q-P+1)2^n (QP+1)2n
  5. 但是这个题卡常了,于是我们要优化。我们发现在枚举素数进行试除的时候,若某个素数 p p p 满足了条件 p 2 > k p^2>k p2>k,则没有必要在枚举了,这时候退出循环就可以了。
  6. 最坏时间复杂度为 O ( 1 0 8 + 28724216 T ) \mathcal O(10^8+28724216T) O(108+28724216T)

代码

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int maxn = 1e8 + 10;
int t, p, q, pi, zs[28724221], ans;
bool vis[maxn];
long long k; 
void Init () 
{
	for (int i = 2; i <= 1e8; i++) 
	{
		if (!vis[i]) zs[++ pi] = i;
		for (int j = 1; j <= pi; j++) 
		{
			if (1ll * zs[j] * i > 1e8) break;
			vis[zs[j] * i] = 1;
			if (i % zs[j] == 0) break;
		}
	}
}
int quickpower (int b) 
{
	if (b == 0) return 1;
	if (b == 1) return 2;
	int mid = quickpower (b / 2);
	if (b & 1) return 2ll * mid * mid % MOD;
	else return 1ll * mid * mid % MOD; 
}
int main ()
{
	Init ();
	scanf ("%d", &t);
	while (t --) 
	{
		scanf ("%lld %d %d", &k, &p, &q);
		int n = 0;
		for (int i = 1; i <= pi && k != 1; i++) 
		{
			if (1ll * zs[i] * zs[i] > k) break;
			if (k % zs[i] == 0) 
			{
				n ++;
				while (k % zs[i] == 0 && k != 1) k /= zs[i];
			}
		}
		if (k != 1) n ++;
		ans = 1ll * quickpower (n) * (q - p + 1) % MOD;
		printf ("%d\n", ans);
	}
	return 0;
}

收获

  1. 知道了自己以前写的线性筛都是假的。

  2. 第一次碰见卡空间复杂度的, 256 M B 256MB 256MB 268435456 268435456 268435456 字节。下图是常见数据类型的所占字节数,bool 型是 1 1 1 字节。
    在这里插入图片描述

  3. 意想不到的卡常优化(思路 5)。

P8927 「GMOI R1-T4」Rain

思路

经过绝对值运算后,将会有 n n n 项符号为正, n n n 项符号为负。为了使答案尽可能地大,我们希望, p a 1 , p a 2 … p a n , q a 1 , q a 2 … q a n pa_1,pa_2\dots pa_n,qa_1,qa_2\dots qa_n pa1,pa2pan,qa1,qa2qan n n n 大项的符号全为正,其余较小的项符号全为负

n = 2 k n=2k n=2k p ≥ q p\ge q pq 的情况为例,我们对 a 1 , a 2 … a 2 k a_1,a_2\dots a_{2k} a1,a2a2k 进行由大到小的排序,得到新的 a 1 , a 2 … a 2 k a_1,a_2\dots a_{2k} a1,a2a2k。令 b 1 , 2 … 2 k b_{1,2\dots2k} b1,22k a 1 , 2 k , 2 , 2 k − 1 , … k , k + 1 a_{1,2k,2,2k-1,\dots k,k+1} a1,2k,2,2k1,k,k+1。下面证明序列 b b b 满足期望。

先不考虑从 2 k 2k 2k 1 1 1 产生的距离,对其他距离进行讨论。当 i i i 为奇数时, ∣ b i − b i + 1 ∣ = p b i − q b i + 1 \lvert bi-b_{i+1}\rvert=pb_i-qb_{i+1} bibi+1=pbiqbi+1;当 i i i 为偶数时,由于 p b i pb_i pbi 递增且 q i + 1 q_{i+1} qi+1 递减,设 i 0 i_0 i0(如果存在的话),使得 p b i 0 ≥ q b i 0 + 1 pb_{i_0}\ge qb_{i_0+1} pbi0qbi0+1,则当 i < i 0 i<i_0 i<i0 时, ∣ p b i − q b i + 1 ∣ = q b i + 1 − p b i \lvert pb_i-qb_{i+1}\rvert=qb_{i+1}-pb_i pbiqbi+1=qbi+1pbi;当 i ≥ i 0 i\ge i_0 ii0 时, ∣ p b i − q b i + 1 ∣ = p b i − q b i + 1 \lvert pb_i-qb_{i+1}\rvert=p{b_i}-qb_{i+1} pbiqbi+1=pbiqbi+1

故符号为正的 2 k − 1 2k-1 2k1 项为, p b 1 , 3 , … , 2 k − 1 , q b 3 , 5 , … , i 0 − 1 , p b i 0 , … , 2 k − 2 pb_{1,3,\dots, 2k-1},qb_{3,5,\dots,i_0-1},pb_{i_0,\dots, 2k-2} pb1,3,,2k1,qb3,5,,i01,pbi0,,2k2
即, p a 1 , 2 , … , k , k + 2 , 2 k − i 0 2 + 1 , q a 2 , 3 , … , i 0 2 pa_{1,2,\dots, k,k+2,2k-\frac{i_0}{2}+1},qa_{2,3,\dots,\frac{i_0}{2}} pa1,2,,k,k+2,2k2i0+1,qa2,3,,2i0

符号为负的 2 k − 1 2k-1 2k1 项为, p a 2 k − i 0 2 + 2 , … , 2 k , q a i 0 2 + 1 , … , 2 k pa_{2k-\frac{i_0}{2}+2,\dots,2k},qa_{\frac{i_0}{2}+1,\dots,2k} pa2k2i0+2,,2k,qa2i0+1,,2k

根据 a a a 的排序方式和 i 0 i_0 i0 的意义可知,正项中的每一个大于负项中的每一个。又 q a 1 qa_1 qa1 p a k + 1 pa_{k+1} pak+1 无论哪项为正,肯定大于上述的负项。故序列 b b b 符合期望。当 n n n 为奇数时,同理可得;当 p < q p<q p<q 时,同理可得,但对 a a a 的排序方式改为“小大小大……”。

时间复杂度为 O ( n log ⁡ n ) \mathcal O(n\log{n}) O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 100;
int n, p, q, a[maxn], cnt, b[maxn];
long long ans;
int read () 
{
	int s = 0, w = 1;
	char ch = getchar ();
	while (ch < '0' || ch > '9') 
	{
		if (ch == '-') w = -1;
		ch = getchar ();
	}
	while (ch >= '0' && ch <= '9') 
	{
		s = s * 10 + ch - '0';
		ch = getchar ();
	}
	return s * w;
}
int main ()
{
	n = read (), p = read (), q = read ();
	for (int i = 1; i <= n; i++)
		a[i] = read ();
	sort (a + 1, a + n + 1);
	for (int i = 1, j = n; i <= j; i++, j--) 
	{
		if (i == j) b[++ cnt] = a[i];
		if (p >= q) 
			b[++ cnt] = a[i], b[++ cnt] = a[j];
		else 
			b[++ cnt] = a[j], b[++ cnt] = a[i];
	}
	for (int i = 1; i <= n; i++) 
	{
		int to = (i == n ? 1 : i + 1);
		ans += abs (1ll * p * b[i] - 1ll * q * b[to]);
	}
	printf ("%lld\n", ans);
	for (int i = 1; i <= n; i++)
		printf ("%d ", b[i]);
	return 0;
}

收获

  1. 敢于推测,敢于证明。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值