8.23 校內模擬賽 題解報告


8.23 校內模擬賽 題解報告

花式白給

T1 SB 數論題 苟比結論題 不過我過了(笑

T2 鬼畜構造題 完全木有想到 暴力騙分苟命

T3 神仙二分題 壓根不會 \(O(n^2)\) 苟命

大概這場考試就是這樣...


關於考試過程以及一些題外話

這次考試是從 T3 開的... 於是就把人玩沒了

看題 嗯 10 分 \(O(n^2)\) 送的

看題 嗯 好像就會 10 分的亞子

看題 嗯 確實就會 10 分的亞子

划拉了半張打草紙之后...

看題 嗯...

然后就把那十分寫了滾蛋了

回去老老實實看 T1

看題 嗯 這啥啊

看題 嗯 好像能做

看題 嗯 好像確實能做

在紙上划拉了一會...

看題 嗯 SB 題

雖然 BS 這個題的代碼寫的很 SB 但是確實是把大樣例過掉了

去騙 T2

先拿了那十分的暴力 然后寫掉二十分的構造 然后就沒有然后了...

看題 好像不太可做的亞子

於是死磕 T3 嗝屁了


結束以后 由於老呂沒來

SB 的 BS 對着電腦搗鼓了半個小時 依舊沒把評測的東西弄好 然后評測一直拖到了下午...


得分情況

100 + 30 + 10 = 140

雖然 T1 的代碼很詭異 但是還是過掉了

T2 和 T3 的暴力都沒掛騙到了四十 大概也就是 T1 的水平了...


題解

T1 Count

要結論的話很簡單

枚舉 \([1, p)\) 范圍內的所有數 \(i\) 記錄 \(i^2 \equiv 1 \pmod p\) 的數的數量

答案: \(ans = \left \lfloor \frac {\varphi(p) - cnt}2 \right \rfloor + cnt\)

Q: 為什么

A:

題目要求滿足

\[xy \equiv 1 \pmod p \]

的無序二元組個數

看一下上面那個東西 大概就能看出來了 就是個逆元

這里的 \(p\) 不一定是質數 所以逆元不一定存在 當 \(a \bot p\)\(a\) 存在模 \(p\) 意義下的逆元且逆元唯一

所以這個題就相當於求與 \(p\) 互質的數的個數 顯然就是 \(\varphi(p)\)

但是題目里要求的無序二元組 而每一個與 \(p\) 互質的 \(x\) 都對應着一個 \(y\)\(x \ne y\) 的時候就會算重 所以這就是上面統計平方模 \(p\)\(1\) 的數的個數的原因了


求那個 \(\varphi\) 的時候 以為只能用素數去篩 於是就先把素數篩出來再用素數篩 \(\varphi\) 忘記可以直接 \(\sqrt n\) 求了...

於是就寫了一個線篩篩素數不曬 \(\varphi\) 函數 篩完素數 拿着篩出來的素數又把 \(\varphi\) 求了一遍的詭異代碼


代碼

/*
  Source: count
*/
#include<cstdio>
#include<cstring>
#define int long long
#define pt putchar(' ')
#define pn putchar('\n')
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*----------------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 5e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
inline void File() {
	freopen("count.in", "r", stdin);
	freopen("count.out", "w", stdout);
}
/*----------------------------------------------------------*/
int p, prime[C << 2], cnt, kcnt, Phi;
bool vis[D];
/*----------------------------------------------------------*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
int power(int x, int y) {int res = 1; for(; y; x = x * x % p, y >>= 1) if(y & 1) res = res * x % p; return res;}
void exgcd(int a, int b, int &d, int &x, int &y)
{
	if(b) exgcd(b, a % b, d, y, x), y -= x * (a / b);
	else d = a, x = 1, y = 0;
}
void pre() {
	for(int i = 2; i ^ p + 1; i++)
	{
		if(!vis[i]) prime[++cnt] = i;
		for(int j = 1; j ^ cnt + 1 && i * prime[j] <= p; j++)
		{
			vis[i * prime[j]] = 1;
			if(!(i % prime[j])) break;
		}
	}
}
void Main() {
	File();
	Phi = p = read(); pre();
	for(int i = 1; i ^ p; i++) if(i * i % p == 1) kcnt++;
	for(int i = 1; i ^ cnt + 1 && prime[i] * prime[i] <= p; i++) if(!(p % prime[i]))
	{
		Phi = Phi / prime[i] * (prime[i] - 1);
		while(!(p % prime[i])) p /= prime[i];
	}
	if(p > 1) Phi = Phi / p * (p - 1);
	Print((Phi - kcnt >> 1) + kcnt);
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}


T2 Color

暴力挺好寫的 直接給結論吧

對於 \(x\) 坐標相同的點 將這些點兩兩配對 如果剩下點則不管 然后每對點之間連邊

對於 \(y\) 坐標相同的點 將這些點兩兩配對 如果剩下點則不管 然后每對點之間連邊

對建成的圖進行染色 能染出來就表示可行 方案也就有了

Q: 為什么

A: 不清楚 意會一下大概是可行的

Q: 能過嗎

A: 能過 而且跑挺快的

Q: 有不合法的情況嗎

A: 不知道 但是沒有判確實過了


代碼

/*
  Source: CF547D Mike and Fish
*/
#include<cstdio>
#include<cstring>
#define pt putchar(' ')
#define pn putchar('\n')
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*----------------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 2e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
inline void File() {
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
}
/*----------------------------------------------------------*/
int n, col[B], lc[B], lr[B];
struct edge {int v, nxt;} e[B << 2];
int head[B], ecnt;
/*----------------------------------------------------------*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void dfs(int u, int c) {
	col[u] = c;
	for(int i = head[u]; i; i = e[i].nxt) if(!~col[e[i].v]) dfs(e[i].v, c ^ 1);
}
void Main() {
	n = read();
	for(int i = 1; i ^ n + 1; i++)
	{
		int x = read(), y = read(); col[i] = -1;
		if(lr[x]) add_edge(lr[x], i), add_edge(i, lr[x]), lr[x] = 0; else lr[x] = i;
		if(lc[y]) add_edge(lc[y], i), add_edge(i, lc[y]), lc[y] = 0; else lc[y] = i;
	}
	for(int i = 1; i ^ n + 1; i++) if(!~col[i]) dfs(i, 0);
	for(int i = 1; i ^ n + 1; i++) putchar(col[i] ? 'r' : 'b');
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}


據說正解是歐拉回路什么的...

然鵝並不會


T3 Sequence

神仙分治題

由於過於麻煩 這里直接說做法了


\(mid = \left \lfloor \frac {l + r}2 \right \rfloor\) 對左邊維護后綴最大值記為 \(max\) 后綴最小值記為 \(min\) 右邊維護前綴最大值\(max\) 前綴最小值\(min\) 前綴最大值的前綴和\(summax\) 前綴最小值的前綴和\(summin\) 前綴最大值與最小值的乘積和\(summul\)

枚舉左側每個位置 對每個 \(i\) 找到第一個位置 \(tmp1\) 使 \(min_{tmp1} \leq min_i\)\(min_{tmp1 - 1} > min_i\) 同時找到第一個位置 \(tmp2\) 使 \(max_{tmp2} \geq max_i\)\(max_{tmp2 - 1} < max_i\) 將右邊的區間分為三段 利用上面維護的各種東西就可以 \(O(1)\) 的算出右端點在右邊區間內的價值和

遞歸處理左右兩部分


各種邊界細節問題極其鬼畜


代碼

/*
  Source: T196991 Sequence
*/
#include<cstdio>
#define int long long
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
/*----------------------------------------------------------*/
const int B = 5e5 + 7;
const int mod = 998244353;
/*----------------------------------------------------------*/
int n, a[B], min[B], max[B], summin[B], summax[B], summul[B], ans;
/*----------------------------------------------------------*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
void solve(int L, int R) {
	if(L == R) {ans = (ans + a[L] * a[L] % mod) % mod; return ;}
	int Mid = L + R >> 1;
	min[Mid] = max[Mid] = a[Mid]; min[Mid + 1] = max[Mid + 1] = a[Mid + 1];
	summin[Mid] = summax[Mid] = summul[Mid] = 0;
	summin[Mid + 1] = summax[Mid + 1] = a[Mid + 1]; summul[Mid + 1] = a[Mid + 1] * a[Mid + 1] % mod;
	for(int i = Mid - 1; i >= L; i--)
		min[i] = Min(min[i + 1], a[i]), max[i] = Max(max[i + 1], a[i]);
	for(int i = Mid + 2; i <= R; i++)
		min[i] = Min(min[i - 1], a[i]), summin[i] = (summin[i - 1] + min[i]) % mod,
		max[i] = Max(max[i - 1], a[i]), summax[i] = (summax[i - 1] + max[i]) % mod,
		summul[i] = (summul[i - 1] + min[i] * max[i] % mod) % mod;
	for(int i = Mid, tmp1 = Mid + 1, tmp2 = Mid + 1; i >= L; i--)
	{
		while(tmp1 <= R && min[tmp1] > min[i]) tmp1++;
		while(tmp2 <= R && max[tmp2] < max[i]) tmp2++;
		int x = Min(tmp1, tmp2), y = Max(tmp1, tmp2);
		ans = (ans + (x - 1 - Mid) * min[i] % mod * max[i] % mod) % mod;
		if(tmp1 < tmp2) ans = (ans + (summin[tmp2 - 1] - summin[tmp1 - 1]) % mod * max[i] % mod) % mod;
		if(tmp1 > tmp2) ans = (ans + (summax[tmp1 - 1] - summax[tmp2 - 1]) % mod * min[i] % mod) % mod;
		ans = ((ans + summul[R] - summul[y - 1]) % mod + mod) % mod;
	}
	solve(L, Mid); solve(Mid + 1, R);
}
void Main() {
	n = read();
	for(int i = 1; i ^ n + 1; i++) a[i] = read();
	solve(1, n);
	Print(ans);
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM