日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2019-08-01 纪中NOIP模拟赛B组

發(fā)布時(shí)間:2023/11/29 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2019-08-01 纪中NOIP模拟赛B组 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

T1?[JZOJ2642] 游戲

題目描述

  Alice和Bob在玩一個(gè)游戲,游戲是在一個(gè)N*N的矩陣上進(jìn)行的,每個(gè)格子上都有一個(gè)正整數(shù)。當(dāng)輪到Alice/Bob時(shí),他/她可以選擇最后一列或最后一行,并將其刪除,但必須保證選擇的這一行或這一列所有數(shù)的和為偶數(shù)。如果他/她不能刪除最后一行或最后一列,那么他/她就輸了。兩人都用最優(yōu)策略來玩游戲,Alice先手,問Alice是否可以必勝?

分析

  這個(gè)說辭...一看就知道是博弈論

  眾所周知,博弈論有兩個(gè)重要結(jié)論:

  1.一個(gè)狀態(tài)是必?cái)顟B(tài)當(dāng)且僅當(dāng)它任意后繼都是必勝狀態(tài)

  2.一個(gè)狀態(tài)是必勝狀態(tài)當(dāng)且僅當(dāng)它存在后繼是必?cái)顟B(tài)

  于是設(shè) $f[i][j]$ 為矩陣為 $i$ 行 $j$ 列時(shí)該回合操作方的狀態(tài)($1$ 為必勝,$0$ 為必?cái)?#xff09;,顯然 $f[1][1]=1$

  同時(shí)需要將 $f[1][i]$ 和 $f[i][1]$ 初始化,還要記錄所有橫軸和縱軸的前綴和

  然后分別討論刪除最后一行和最后一列時(shí)的后繼狀態(tài),若該行或該列無法被刪除,則該后繼視為必勝

  考場(chǎng)上寫這題的時(shí)候已經(jīng)不早了,感覺有點(diǎn)慌,幸好最后過了

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define N 1005int T, n; int g[N][N], f[N][N], p1[N][N], p2[N][N];int main() {scanf("%d", &T);while (T--) {scanf("%d", &n);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {scanf("%d", &g[i][j]);p1[i][j] = p1[i][j - 1] + g[i][j];p2[i][j] = p2[i - 1][j] + g[i][j];}f[1][1] = 1;for (int i = 2; i <= n; i++) {int t1, t2;if (p1[1][i] % 2) t1 = 1;else t1 = 0;if (p2[1][i] % 2) t2 = 1;else if (f[1][i - 1]) t2 = 1;else t2 = 0;if (t1 && t2) f[1][i] = 0;else f[1][i] = 1;}for (int i = 2; i <= n; i++) {int t1, t2;if (p2[i][1] % 2) t2 = 1;else t2 = 0;if (p2[i][1] % 2) t1 = 1;else if (f[i - 1][1]) t1 = 1;else t1 = 0;if (t1 && t2) f[1][i] = 0;else f[i][1] = 1;}for (int i = 2; i <= n; i++)for (int j = 2; j <= n; j++) {int t1, t2;if (p1[i][j] % 2) t1 = 1;else if (f[i - 1][j]) t1 = 1;else t1 = 0;if (p2[i][j] % 2) t2 = 1;else if (f[i][j - 1]) t2 = 1;else t2 = 0;if (t1 && t2) f[i][j] = 0;else f[i][j] = 1;}if (f[n][n]) printf("W\n");else printf("L\n");}return 0; } View Code

T2?[JZOJ2643] 六邊形

題目描述

  棋盤是由許多個(gè)六邊形構(gòu)成的,共有5種不同的六邊形編號(hào)為1到5,棋盤的生成規(guī)則如下:

  1.從中心的一個(gè)六邊形開始,逆時(shí)針向外生成一個(gè)個(gè)六邊形。

  2.對(duì)于剛生成的一個(gè)六邊形,我們要確定它的種類,它的種類必須滿足與已生成的相鄰的六邊形不同。

  3.如果有多個(gè)種類可以選,我們選擇出現(xiàn)次數(shù)最少的種類。

  4.情況3下還有多個(gè)種類可以選,我們選擇數(shù)字編號(hào)最小的。

  現(xiàn)在要你求第N個(gè)生成的六邊形的編號(hào)?

  前14個(gè)六邊形生成圖如下:

分析

  這是個(gè)純模擬,感覺沒有什么要分析的

  主要就是要多注意細(xì)節(jié),考場(chǎng)上少寫了一句代碼,直接掉到了 $45.5$ 分

  而且每次一寫模擬就寫得賊慢

//考場(chǎng)上寫得有點(diǎn)繁瑣 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define N 10005int T, n, c = 2, now = 8, s, e, ok, g1, g2; int q[25], g[N], book[6], sum[6];int main() {scanf("%d", &T);for (int i = 1; i <= T; i++) {scanf("%d", q + i);n = max(n, q[i]);}g[1] = 1; g[2] = 2; g[3] = 3;g[4] = 4; g[5] = 5; g[6] = 2; g[7] = 3;sum[1] = sum[4] = sum[5] = 1;sum[2] = sum[3] = 2; sum[0] = inf;s = 2; e = 7;while (++c) {for (int i = 1; i <= 6; i++) {for (int j = 1; j < c; j++) {memset(book, 0, sizeof book);int minsum = inf;if (j != c - 1) {if (now == e + 1) {book[g[s]] = book[g[e]] = 1;for (int k = 1; k <= 5; k++)if (!book[k])minsum = min(minsum, sum[k]);for (int k = 1; k <= 5; k++)if (!book[k] && sum[k] == minsum) {g[now++] = k; sum[k]++; break;}g1 = s; g2 = s + 1; s = e + 1;}else {book[g[g1]] = book[g[g2]] = book[g[now - 1]] = 1;for (int k = 1; k <= 5; k++)if (!book[k])minsum = min(minsum, sum[k]);for (int k = 1; k <= 5; k++)if (!book[k] && sum[k] == minsum) {g[now++] = k; sum[k]++; break;}g1++; g2++;}}else {if (i == 6) e = now, book[g[s]] = 1;book[g[g1]] = book[g[now - 1]] = 1;for (int k = 1; k <= 5; k++)if (!book[k])minsum = min(minsum, sum[k]);for (int k = 1; k <= 5; k++)if (!book[k] && sum[k] == minsum) {g[now++] = k; sum[k]++; break;}}if (now > n) {ok = 1; break;}}if (ok) break;}if (ok) break;}for (int i = 1; i <= T; i++)printf("%d\n", g[q[i]]);return 0; } View Code

T3?[JZOJ2644] 數(shù)列

題目描述

  給你一個(gè)長(zhǎng)度為N的正整數(shù)序列,如果一個(gè)連續(xù)的子序列,子序列的和能夠被K整除,那么就視此子序列合法,求原序列包括多少個(gè)合法的連續(xù)子序列?

  對(duì)于一個(gè)長(zhǎng)度為8的序列,K=4的情況:2, 1, 2, 1, 1, 2, 1, 2 。它的答案為6,子序列是位置1->位置8,2->4,2->7,3->5,4->6,5->7。

分析

  看到題目就先寫了前綴和枚舉區(qū)間 $O(n^2)$ 暴力 $30 \, pts$

  當(dāng)時(shí)看了半天覺得這是最可做的一題,結(jié)果看了數(shù)據(jù)范圍還是沒想出來 $O(n \, log \, n)$ 做法

  結(jié)果考完試下午看了下大家的討論,發(fā)現(xiàn)正解是 $O(k)$

  具體就是把每個(gè)前綴和按 $k$ 取模,記錄每個(gè)余數(shù)出現(xiàn)的次數(shù) $sum$

  顯然,前綴和所得余數(shù)相同的的兩項(xiàng)之間的區(qū)間和,一定能被 $k$ 整除

  所以在余數(shù)相同的項(xiàng)中,我們可以任意挑選兩項(xiàng)組成一個(gè)合法區(qū)間

  因此答案為 $\sum\limits_{i=0}^{k-1} \binom{sum[i]}{2}$

  要注意,第 $0$ 項(xiàng)的前綴和余數(shù)視為 $0$

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define ll long long #define N 50005 #define K 1000005int T, n, k, x; int pre[N], sum[K]; ll ans, c[K];int main() {c[2] = 1;for (int i = 3; i <= N; i++)c[i] = c[i - 1] + i - 1;scanf("%d", &T);while (T--) {ans = 0;scanf("%d%d", &k, &n);for (int i = 1; i <= k; i++) sum[i] = 0;sum[0] = 1;for (int i = 1; i <= n; i++) {scanf("%d", &x);pre[i] = (pre[i - 1] + x) % k;sum[pre[i]]++;}for (int i = 0; i < k; i++)ans += c[sum[i]];printf("%lld\n", ans);}return 0; } View Code

轉(zhuǎn)載于:https://www.cnblogs.com/Pedesis/p/11284483.html

總結(jié)

以上是生活随笔為你收集整理的2019-08-01 纪中NOIP模拟赛B组的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。