題目名稱 正確答案? 序列問題 長途旅行 英文名稱 answer sequence travel 輸入文件名 answer.in sequence.in travel.in 輸出文件名 answer.out sequence.out travel.out 時間限制 1s 1s 1s 空間限制 ? 256M 256M 256M 測試點數(shù)目 20 20 10 測試點分值 5 5 10 是否有部分分 無 無 無 題目類型 傳統(tǒng) 傳統(tǒng) 傳統(tǒng) 是否有 SPJ 無 無 無
?
正確答案 全國信息學(xué)奧林匹克聯(lián)賽( ( NOIP2014) 復(fù) 賽 模擬題 Day1 長樂一中 【題目描述】 小 H 與小 Y 剛剛參加完 UOIP 外卡組的初賽,就迫不及待的跑出考場對答案。 “吔,我的答案和你都不一樣!”,小 Y 說道,”我們?nèi)フ疑駹膫儐柎鸢赴伞薄?br />外卡組試卷中共有 m 道判斷題,小 H 與小 Y 一共從其他 n 個神犇那問了答案。之后又 從小 G 那里得知, 這 n 個神犇中有 p 個考了滿分, q 個考了零分, 其他神犇不為滿分或零分。 這可讓小 Y 與小 H 犯了難。你能幫助他們還原出標準答案嗎?如有多解則輸出字典序最小 的那個。無解輸出-1。 【 輸入格式】 第一行四個整數(shù) n, m, p, q,意義如上描述。 接下來 n 行,每一行 m 個字符’N’或’Y’,表示這題這個神犇的答案。 【 輸出格式】 僅一行,一個長度為 m 的字符串或是-1。 【 樣例輸入】 2 2 2 0 YY YY 【 樣例輸出】 YY 【 數(shù)據(jù)范圍】 30% : n <= 100. 60% : n <= 5000 , m <= 100. 100% : 1 <= n <= 30000 , 1 <= m <= 500. 0 <= p , q 且 p + q <= n.
T1: 30%: O(n ^ 2 * m)暴力判斷。 100%: 很顯然答案的可能性最多只有 n 種,所以我們將所有人的答案按字典序排序后枚舉 將每個人的答案作為正確答案來進行判斷。 由于是判斷題, 若當前人的答案為正確答 案則零分者的答案也就確定了, 那么只需統(tǒng)計出這兩種答案的人數(shù)判斷是否滿足題意 即可。這一步使用字符串哈希即可解決。 另外要注意 p = 0 和 p = q = 0 的情況。
1 #include <algorithm>
2 #include <iostream>
3 #include <cstring>
4 #include <cstdio>
5 #include <cmath>
6 using namespace std;
7
8 const int N = 3e4 +
2 , M = 5e2 +
2 , sed =
31 , SED =
131 , mod =
70177 , MOD =
92311 ;
9 int n, m, p, q, ans, hash[N], HASH[N];
10 int top, info[mod], nxt[N *
2 ], fet[N *
2 ], cnt[N *
2 ];
11 struct node {
12 char s[M];
13 inline
bool operator < (
const node &b)
const {
14 return strcmp(s, b.s) <
0 ;
15 }
16 } a[N];
17
18 inline
void Insert(
const int &x,
const int &
y) {
19 for (
int k = info[x]; k; k =
nxt[k])
20 if (fet[k] ==
y) {
21 ++cnt[k];
return ;
22 }
23 nxt[++top] = info[x]; info[x] =
top;
24 fet[top] = y; cnt[top] =
1 ;
25 return ;
26 }
27
28 inline
int Query(
const int &x,
const int &
y) {
29 for (
int k = info[x]; k; k =
nxt[k])
30 if (fet[k] == y)
return cnt[k];
31 return 0 ;
32 }
33
34 inline
void Solve1() {
35 int tmp, TMP; ans = -
1 ;
36 for (
int i =
0 ; i < n; ++
i) {
37 tmp = TMP =
0 ;
38 for (
int j =
0 ; j < m; ++
j) {
39 tmp = (tmp * sed + (a[i].s[j] ==
' N ' )) %
mod;
40 TMP = (TMP * SED + (a[i].s[j] ==
' N ' )) %
MOD;
41 }
42 hash[i] = tmp, HASH[i] =
TMP;
43 Insert(tmp, TMP);
44 }
45 for (
int i =
0 ; i < n; ++
i)
46 if (Query(hash[i], HASH[i]) ==
p) {
47 tmp = TMP =
0 ;
48 for (
int j =
0 ; j < m; ++
j) {
49 tmp = (tmp * sed + (a[i].s[j] ==
' Y ' )) %
mod;
50 TMP = (TMP * SED + (a[i].s[j] ==
' Y ' )) %
MOD;
51 }
52 if (Query(tmp, TMP) ==
q) {
53 ans = i;
break ;
54 }
55 }
56 if (ans != -
1 ) printf(
" %s\n " , a[ans].s);
57 else puts(
" -1 " );
58 return ;
59 }
60
61 char cur[M];
62 inline
void Solve2() {
63 int tmp, TMP; ans = -
1 ;
64 for (
int i =
0 ; i < n; ++
i) {
65 tmp = TMP =
0 ;
66 for (
int j =
0 ; j < m; ++
j) {
67 tmp = (tmp * sed + (a[i].s[j] ==
' N ' )) %
mod;
68 TMP = (TMP * SED + (a[i].s[j] ==
' N ' )) %
MOD;
69 }
70 hash[i] = tmp, HASH[i] =
TMP;
71 Insert(tmp, TMP);
72 }
73 for (
int i = n -
1 ; i >=
0 ; --
i)
74 if (Query(hash[i], HASH[i]) ==
q) {
75 tmp = TMP =
0 ;
76 for (
int j =
0 ; j < m; ++
j) {
77 tmp = (tmp * sed + (a[i].s[j] ==
' Y ' )) %
mod;
78 TMP = (TMP * SED + (a[i].s[j] ==
' Y ' )) %
MOD;
79 }
80 if (Query(tmp, TMP) ==
p) {
81 ans = i;
break ;
82 }
83 }
84 if (ans != -
1 ) {
85 for (
int i =
0 ; i < m; ++
i)
86 cur[i] = a[ans].s[i] ==
' N ' ?
' Y ' :
' N ' ;
87 printf(
" %s\n " , cur);
88 }
89 else puts(
" -1 " );
90 return ;
91 }
92
93 void Solve3() {
94 int tmp, TMP;
95 for (
int i =
0 ; i < n; ++
i) {
96 tmp = TMP =
0 ;
97 for (
int j =
0 ; j < m; ++
j) {
98 tmp = (tmp * sed + (a[i].s[j] ==
' N ' )) %
mod;
99 TMP = (TMP * SED + (a[i].s[j] ==
' N ' )) %
MOD;
100 }
101 Insert(tmp, TMP);
102 tmp = TMP =
0 ;
103 for (
int j =
0 ; j < m; ++
j) {
104 tmp = (tmp * sed + (a[i].s[j] ==
' Y ' )) %
mod;
105 TMP = (TMP * SED + (a[i].s[j] ==
' Y ' )) %
MOD;
106 }
107 Insert(tmp, TMP);
108 }
109 bool flag =
true ;
110 for (
int i =
0 ; i < m; ++i) cur[i] =
' N ' ;
111 do {
112 tmp = TMP =
0 ;
113 for (
int j =
0 ; j < m; ++
j) {
114 tmp = (tmp * sed + (cur[j] ==
' N ' )) %
mod;
115 TMP = (TMP * SED + (cur[j] ==
' N ' )) %
MOD;
116 }
117 if (Query(tmp, TMP) ==
0 ) {
118 flag =
true ;
break ;
119 }
120 flag =
false ;
121 for (
int j = m -
1 ; j >=
0 ; --
j)
122 if (cur[j] ==
' Y ' ) cur[j] =
' N ' ;
123 else {
124 cur[j] =
' Y ' ; flag =
true ;
break ;
125 }
126 }
while (flag);
127 if (flag) printf(
" %s\n " , cur);
128 else puts(
" -1 " );
129 return ;
130 }
131
132 int main() {
133 freopen(
" answer.in " ,
" r " , stdin);
134 freopen(
" answer.out " ,
" w " , stdout);
135 scanf(
" %d%d%d%d " , &n, &m, &p, &
q);
136 for (
int i =
0 ; i < n; ++i) scanf(
" %s " , a[i].s);
137 sort(a, a +
n);
138 if (p) Solve1();
139 else if (q) Solve2();
140 else Solve3();
141 fclose(stdin); fclose(stdout);
142 return 0 ;
143 }
View Code 2. 序列問題 【 題目描述】 小 H 是個善于思考的學(xué)生,她正在思考一個有關(guān)序列的問題。 她的面前浮現(xiàn)出了一個長度為 n 的序列{ai},她想找出兩個非空的集合 S、T。 這兩個集合要滿足以下的條件: 1. 兩個集合中的元素都為整數(shù),且都在 [1, n] 里,即 Si,Ti ∈ [1, n]。 2. 對于集合 S 中任意一個元素 x,集合 T 中任意一個元素 y,滿足 x < y。 3. 對于大小分別為 p, q 的集合 S 與 T,滿足 a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq]. 小 H 想知道一共有多少對這樣的集合(S,T),你能幫助她嗎? 【輸入格式】 第一行,一個整數(shù) n 第二行,n 個整數(shù),代表 ai。 【 輸出格式】 僅一行,表示最后的答案。 【 樣例輸入】 4 1 2 3 3 【 樣例輸出】 4 【 樣例解釋】 S = {1,2}, T = {3}, 1 ^ 2 = 3 = 3 (^為異或) S = {1,2}, T = {4}, 1 ^ 2 = 3 = 3 S = {1,2}, T = {3,4} 1 ^ 2 = 3 & 3 = 3 (&為與運算) S = {3}, T = {4} 3 = 3 = 3 【 數(shù)據(jù)范圍】 30%: 1 <= n <= 10 60%: 1 <= n <= 100 100%: 1 <= n <= 1000, 0 <= ai < 1024
T2: 30%:枚舉每個數(shù)所在的集合或者不選,然后判定即可。復(fù)雜度 O(n*3^n)。 60%: Dp, 兩個數(shù)相等就相當于兩個數(shù)的 xor 為 0。 設(shè) f[i][j][k=0..2]代表 處理到第 I 個數(shù), 如果 k = 1 代表 and 值為 j,如果 k = 2 代表 xor 值為 j,如果 k = 0 則代表一個元素都沒 取。所以很容易得到方程: f[i][j][0] = f[i + 1][j][0] f[i][j & ai][1] = f[i + 1][j][1] + f[i + 1][j][0] + f[i + 1][j & ai][1] f[i][j ^ ai][2] = f[i + 1][j][1] + f[i + 1][j][2] + f[i + 1][j ^ ai][2]; 最后 f[1][0][2]就是答案, 復(fù)雜度為 O(n * 1024 * 3) DP 還可以分開用 f[i][j]和 g[i][j]表示前 i 個 xor 值為 j,后 i 個 and 值為 j 的方案數(shù), 隨后枚舉分界點 k 來求總方案數(shù)。復(fù)雜度 O(n * 1024 * 3)。 100%:滿分數(shù)據(jù)需要高精,答案位數(shù)較大,需要進行壓位來防止 TLE,因為不知道答案的 位數(shù)究竟多大,壓位后高精數(shù)組仍需要開的較大一些,所以原 DP 的數(shù)組滾動即可。
1 #include <algorithm>
2 #include <iostream>
3 #include <cstring>
4 #include <cstdio>
5 #include <cmath>
6 using namespace std;
7
8 typedef
long long ll;
9 const int N =
1001 , M =
1024 , W =
1e9;
10 int n, cur, nxt, va, vx, p[N];
11
12 struct huge_int {
13 int len, a[
40 ];
14 huge_int(): len(
1 ) { memset(a,
0 ,
sizeof (a)); }
15
16 inline
void operator += (
const huge_int &
b) {
17 b.len > len ? len = b.len :
0 ;
18 for (
int i =
1 ; i <= len; ++
i) {
19 a[i] +=
b.a[i];
20 if (a[i] >= W) ++a[i +
1 ], a[i] -=
W;
21 }
22 if (a[len +
1 ]) ++
len;
23 return ;
24 }
25
26 inline
void print() {
27 printf(
" %d " , a[len]);
28 for (
int i = len -
1 ; i; --
i)
29 printf(
" %09d " , a[i]);
30 puts(
"" );
return ;
31 }
32 } f[
2 ][M][
3 ];
33
34 char ch;
35 int read() {
36 while (ch = getchar(), ch <
' 0 ' || ch >
' 9 ' );
37 int res = ch -
48 ;
38 while (ch = getchar(), ch >=
' 0 ' && ch <=
' 9 ' ) res = res *
10 + ch -
48 ;
39 return res;
40 }
41
42 int main() {
43 freopen(
" sequence.in " ,
" r " , stdin);
44 freopen(
" sequence.out " ,
" w " , stdout);
45 n =
read();
46 for (
int i = n; i; --i) p[i] =
read();
47 f[
0 ][
1023 ][
0 ].a[
1 ] =
1 ;
48 for (
int i =
0 ; i < n; ++
i) {
49 nxt = cur ^
1 ;
50 for (
int j =
0 ; j < M; ++
j)
51 for (
int k =
0 ; k <=
2 ; ++
k)
52 f[nxt][j][k] =
f[cur][j][k];
53 for (
int j =
0 ; j < M; ++
j) {
54 va = p[i +
1 ] & j, vx = p[i +
1 ] ^
j;
55 f[nxt][va][
1 ] += f[cur][j][
0 ]; f[nxt][va][
1 ] += f[cur][j][
1 ];
56 f[nxt][vx][
2 ] += f[cur][j][
1 ]; f[nxt][vx][
2 ] += f[cur][j][
2 ];
57 }
58 cur ^=
1 ;
59 }
60 f[cur][
0 ][
2 ].print();
61 fclose(stdin); fclose(stdout);
62 return 0 ;
63 }
View Code 3. 長途旅行 【 題目描述】 JY 是一個愛旅游的探險家,也是一名強迫癥患者。現(xiàn)在 JY 想要在 C 國進行一次長途 旅行,C 國擁有 n 個城市(編號為 0,1,2...,n - 1),城市之間有 m 條道路,可能某個城市到自己 有一條道路,也有可能兩個城市之間有多條道路,通過每條道路都要花費一些時間。JY 從 0 號城市開始出發(fā),目的地為 n – 1 號城市。由于 JY 想要好好參觀一下 C 國,所以 JY 想要 旅行恰好 T 小時。為了讓自己的旅行更有意思,JY 決定不在任何一個時刻停留(走一條到城 市自己的路并不算停留)。JY 想知道是否能夠花恰好 T 小時到達 n – 1 號城市(每個城市可 經(jīng)過多次) 。現(xiàn)在這個問題交給了你。 若可以恰好到達輸出“Possible”否則輸出“Impossible” 。(不含引號)。 【 輸入格式】 第一行一個正整數(shù) Case,表示數(shù)據(jù)組數(shù)。 每組數(shù)據(jù)第一行 3 個整數(shù),分別為 n, m, T。 接下來 m 行,每行 3 個整數(shù) x, y, z,代表城市 x 和城市 y 之間有一條耗時為 z 的雙向邊。 【 輸出格式】 對于每組數(shù)據(jù)輸出”Possible”或者”Impossible”. 【 樣例輸入】 2 3 3 11 0 2 7 0 1 6 1 2 5 2 1 10000 1 0 1 【 樣例輸出】 Possible Impossible 【 樣例解釋】 第一組:0 -> 1 -> 2 :11 第二組:顯然偶數(shù)時間都是不可能的。 【 數(shù)據(jù)范圍】 30%: T <= 10000 另有 30%: n <= 5 , m <= 10. 100%: 2 <= n <= 50 , 1 <= m <= 100 , 1 <= z <= 10000 , 1 <= T <= 10^18 , Case <= 5.
T3: 30%: 當 T<= 10000 的時候,可以設(shè) vis[i][j] 代表到達第 i 個點時間為 j 是否合法。 這樣是 O(T*m),可以拿到小數(shù)據(jù)。 另外的那 30%:各種奇怪的騙分方法。選手自行考慮。 100%: 當 T 很大的時候,我們考慮 如果 0 -> x -> n - 1 路徑時間為 T,且 從 x 出發(fā)有一個時 間為 d 的環(huán),則 一定存在一個 K 滿足 K + p*d = T(至少 T 滿足條件) ,這樣我們就能繞著 環(huán)走 p 次就能構(gòu)成一條時間為 T 的路徑。 顯然要求的路徑一定經(jīng)過 0,而且在合法情況下從 0 號點出發(fā)一定存在一條邊,否則 0 號點和 n - 1 號就是不聯(lián)通的。 隨便取一條邊時間為 d, 則能構(gòu)成從 0 號點出發(fā)的一個時間為 2d 的環(huán)。這樣原題就化為最短路問題了,dis[i][j] 代表到達 i 號點,時間為 j + p * 2d,最小 的 j+p*2d, 最后判斷 dis[n -1][T % 2d] 是否小于等于 T 即可。 實際上就是在 30%的基礎(chǔ)上縮減狀態(tài)。 時間復(fù)雜度為 O(m*d)。
1 #include <algorithm>
2 #include <iostream>
3 #include <cstring>
4 #include <cstdio>
5 #include <cmath>
6 #include <queue>
7 using namespace std;
8
9 #define X first
10 #define Y second
11 #define mk make_pair
12 typedef pair<
int ,
int >
DI;
13 typedef
long long ll;
14 const int N =
51 , M =
201 , K =
20001 ;
15 int n, m, len, u, v, c, Case;
16 int tot, info[N], nxt[M], go[M], val[M];
17 ll T, INF, dist[N][K];
18 queue<DI>
que;
19 bool vis[N][K];
20
21 inline
void SetE(
int x,
int y,
int z) {
22 nxt[++tot] = info[x]; info[x] = tot; go[tot] = y; val[tot] =
z;
23 nxt[++tot] = info[y]; info[y] = tot; go[tot] = x; val[tot] =
z;
24 return ;
25 }
26
27 inline
void Spfa() {
28 int x, y, p, q; ll v;
29 memset(dist,
63 ,
sizeof (dist));
30 dist[
0 ][
0 ] =
0 ; que.push(mk(
0 ,
0 ));
31 while (!
que.empty()) {
32 DI top =
que.front(); que.pop();
33 x = top.X, p = top.Y; vis[x][p] =
false ;
34 for (
int k = info[x]; y = go[k], k; k =
nxt[k]) {
35 v = dist[x][p] + val[k]; q = v %
len;
36 if (dist[y][q] >
v) {
37 dist[y][q] =
v;
38 if (!
vis[y][q]) {
39 vis[y][q] =
true ;
40 que.push(mk(y, q));
41 }
42 }
43 }
44 }
45 return ;
46 }
47
48 char ch;
49 inline
int read() {
50 while (ch = getchar(), ch <
' 0 ' || ch >
' 9 ' );
51 int res = ch -
48 ;
52 while (ch = getchar(), ch >=
' 0 ' && ch <=
' 9 ' ) res = res *
10 + ch -
48 ;
53 return res;
54 }
55 inline ll Read() {
56 while (ch = getchar(), ch <
' 0 ' || ch >
' 9 ' );
57 ll res = ch -
48 ;
58 while (ch = getchar(), ch >=
' 0 ' && ch <=
' 9 ' ) res = res *
10 + ch -
48 ;
59 return res;
60 }
61
62 int main() {
63 freopen(
" travel.in " ,
" r " , stdin);
64 freopen(
" travel.out " ,
" w " , stdout);
65 Case =
read();
66 while (Case--
) {
67 n = read(), m = read(); T =
Read();
68 memset(info,
0 ,
sizeof (info)); tot =
0 ;
69 for (
int i =
1 ; i <= m; ++
i) {
70 u = read(), v = read(); c =
read();
71 SetE(u, v, c);
72 }
73 if (!info[
0 ]) puts(
" Impossible " );
74 else {
75 len =
10001 ;
76 for (
int k = info[
0 ]; k; k =
nxt[k])
77 if (val[k] < len) len =
val[k];
78 len *=
2 ; Spfa();
79 if (dist[n -
1 ][T % len] <= T) puts(
" Possible " );
80 else puts(
" Impossible " );
81 }
82 }
83 fclose(stdin); fclose(stdout);
84 return 0 ;
85 }
View Code ?
轉(zhuǎn)載于:https://www.cnblogs.com/J-william/p/6063373.html
總結(jié)
以上是生活随笔 為你收集整理的全国信息学奥林匹克联赛 ( NOIP2014) 复赛 模拟题 Day1 长乐一中 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。