USACO 3.2 分析

來源:互聯網
上載者:User

 題目一:Factorials

題目大意:求n!的最後非0位。

演算法:類比

1.2的因子的個數顯然比5多很多;

2.可以預先根據5的個數估計出末尾0的個數,然後只需儲存多餘2的個數,去更新末位的值;

3.實際做的時候沒有想到上述方法,而是鬼使神差地想到儲存末5位,但是無法證明!

 #include <stdio.h><br />#include <string.h><br />unsigned int s[32][32];<br />void dfs(unsigned int m, int leftone, int dep) {<br />//printf("%d %d %d/n", m, leftone, dep);<br />if (dep == 0) {<br />printf("/n");<br />return;<br />}<br />if (m <= s[dep-1][leftone]) {<br />printf("0");<br />dfs(m, leftone, dep-1);<br />} else {<br />printf("1");<br />dfs(m-s[dep-1][leftone], leftone-1, dep-1);<br />}<br />}<br />int main(){<br />freopen("kimbits.in", "r", stdin);<br />freopen("kimbits.out", "w", stdout);<br />int n, k, m, i, j;<br />scanf("%d %d %u", &n, &k, &m);//%u used for reading unsigned 10-based numbers<br />memset(s,0,sizeof(s));<br />for (j = 0; j <= k; j++) s[0][j] = 1;<br />for (i = 1; i <= n; i++) {<br />s[i][0] = 1;<br />for (j = 1; j <= k; j++) s[i][j] = s[i-1][j-1] + s[i-1][j];<br />}<br />dfs(m, k, n);<br />return 0;<br />}<br />

 

題目二:Stringsobits

題目大意:在所有長度為N的1的位元不超過K的位元中(包含前置0),求出第I大的數

演算法:DP

狀態轉移方程:S[I][J]表示長度為I用1的個數不大於J的位元的個數;

S[I][J] = S[I-1][J]+S[I-1][J-1],很像C(A,B)的遞推公式啊!

初始條件:s[0][i] = 1,1 <= i <= K

還有一點要注意的是2^31 超過LONGINT的表示範圍,可以用UNSIGHED LONGINT,讀入格式scanf("%u", &a)

#include <stdio.h><br />#include <string.h><br />int main(){<br />freopen("fact4.in", "r", stdin);<br />freopen("fact4.out", "w", stdout);<br />int n;<br />scanf("%d", &n);<br />int s = 1;<br />for (int i = 1; i <= n; i++)<br />if (i % 5 != 0)s = (s*i) % 100000; else {<br />int j = i;<br />while (j % 5 == 0) s >>= 1, j /= 5;<br />s = (s*j) % 100000;<br />}<br />printf("%d/n", s%10);<br />return 0;<br />}<br />

 

題目三:Spinning Wheels

題目大意:有若干個有缺口的轉動著的輪子,轉的過程是離散的,以時間1為基本單位,求出什麼時候在某處光線可以通過。

一種思路是狀態仍是離散儲存,只儲存起始點和末端點,用時間更新初始座標,判斷的時候考慮到有些段可能跨越360的臨界,就要分別判斷是在360內還是360外。

特別注意:只要有一點縫隙,光就可以過!

 #include <stdio.h><br />#include <string.h><br />int speed[5], t[5];<br />int a[5][5], b[5][5];<br />int main(){<br />freopen("spin.in", "r", stdin);<br />freopen("spin.out", "w", stdout);<br />int i, j, k;<br />for (i = 0; i < 5; i++) {<br />scanf("%d %d", &speed[i], &t[i]);<br />for (j = 0; j < t[i]; j++) {<br />scanf("%d %d", &a[i][j], &b[i][j]);<br />b[i][j] += a[i][j];<br />b[i][j] %= 360;<br />}<br />}<br />int tt = 0;<br />bool find = false;<br />do {<br />//CHECK<br />for (i = 0; i < 360 && !find; i++) {<br />bool go = true;<br />for (j = 0; j < 5; j++) {<br />bool flag = false;//if any wedge can through it then flag = true<br />for (k = 0; k < t[j] && !flag; k++) {<br />if (b[j][k] < a[j][k]) b[j][k] += 360;<br />if (a[j][k] <= i && i <= b[j][k] || a[j][k] <= i+360 && i+360 <= b[j][k]) flag = true;<br />//the light between also go through [1,2],[2,3],two ways it go through<br />b[j][k] %= 360;<br />}<br />if (!flag) {<br />go = false;<br />break;<br />}<br />}<br />if (go) {<br />find = true;<br />break;<br />}<br />}<br />if (find) break;<br />//Rotate<br />tt++;<br />for (i = 0; i < 5; i++)<br />for (j = 0; j < t[i]; j++) {<br />a[i][j] = (a[i][j] + speed[i]) % 360;<br />b[i][j] = (b[i][j] + speed[i]) % 360;<br />}<br />} while(tt <= 360);<br />if (find) printf("%d/n", tt); else printf("none/n");<br />return 0;<br />}<br />

 

還有一種思路是用BOOL來儲存狀態,效率相對較低;

 

題目四:Feed Ratios

1.由於資料比較小,可以BRUTE FORCE,關鍵在於3點共線判斷的方法,不推薦用斜率的方法去做,最好用向量的方法去做;

#include <stdio.h><br />#include <string.h><br />int s[4][4], get[4];<br />bool check(int i, int j) {<br />if (s[0][i]*get[j]-s[0][j]*get[i] == 0) return true; else return false;<br />}<br />int main(){<br />freopen("ratios.in", "r", stdin);<br />freopen("ratios.out", "w", stdout);<br />for (int i = 0; i <= 3; i++)<br />for (int j = 1; j <= 3; j++)<br />scanf("%d", &s[i][j]);<br />int tot = 300, totx, toty, totz, t, tt;<br />for (int i = 0; i < 100 && i < tot; i++)<br />for (int j = 0; j < 100 && i+j < tot; j++)<br />for (int k = 0; k < 100 && i+j+k < tot && i+j+k>0; k++) {<br />for (int l = 1; l <= 3; l++)<br />get[l] = i*s[1][l] + j*s[2][l] + k*s[3][l];<br />tt = 0;<br />for (int l = 1; l <= 3; l++)<br />if (get[l] != 0 && s[0][l] != 0) {<br />tt = get[l] / s[0][l];<br />break;<br />}<br />bool flag = true;<br />for (int l = 1; l <= 3 && flag; l++)<br />if (tt * s[0][l] != get[l]) flag = false;<br />/*<br />if (tt > 0 && check(1,2) && check(2,3) && check(3,1)) {// 也可用行列式去做<br />*/<br />if (flag) {<br />tot = i+j+k;<br />totx = i;<br />toty = j;<br />totz = k;<br />t = tt;<br />}<br />}<br />if (tot == 300) printf("NONE/n"); else printf("%d %d %d %d/n", totx, toty, totz, t);<br />return 0;<br />}<br />

2.本題可以用Cream方程組的知識去做,以下是USACO官方的解答When you combine multiples of mixtures, you can look at it as a multiplication of a matrix by a vector. For example, 8*(1:2:3) + 1*(3:7:1) + 5*(2:1:2) = (21:28:35) = 7*(3:4:5) can be seen as </p><p>[ 1 3 2 ] [ 8 ]<br />[ 2 7 1 ] * [ 1 ] = 7 [3 4 5]<br />[ 3 1 2 ] [ 5 ] </p><p>The matrix and the goal ratio vector (3:4:5 in this case) are given; what we have to find is the multiple vector (8:1:5 in this case) and the proportionality costant (7 here). This is like solving a system of linear equations. We can write it as </p><p>AX = kB.</p><p>Now, if we use Cramer's Rule, and let D = determinant of A, then </p><p>X_1 = k D_1 / D<br />X_2 = k D_2 / D<br />X_3 = k D_3 / D,</p><p>where D_1 is the determinant of the matrix A with the 1st column is replaced by B, D_2 is the determinant of the matrix A with the 2nd column is replaced by B, D_3 is the determinant of the matrix A with the 3rd column is replaced by B. (see a Linear Algebra textbook on why this works.) ,P> We are looking for integral solutions. If D = 0, no solutions. Otherwise, let k = D, and then X_1 = D_1, etc. If these values (X_1,X_2,X_3, _and_ k) all have a greatest common factor above 1, divide them all by that factor, as we are looking for the smallest possible solutions.<br />Now, if some of the numbers is greater than 100, we have not found a feasible solution, so we output `NONE'. Otherwise, the triple (X_1,X_2,X_3) is output, as well as the value k. </p><p>

 

題目五:Magic Squares

演算法:BFS

1.康托展開(Cantor),給出一個1-N的排列,求1-N的全排列字典序中的位置;

2.康托展開的逆運算是給出位置,找到這個排列。

3.這道題要用Cantor + Hash可以有效節約空間

#include <stdio.h><br />#include <string.h><br />const<br />int d[3][8] = {{7,6,5,4,3,2,1,0}, {3,0,1,2,5,6,7,4}, {0,6,1,3,4,2,5,7}}, max = 40321;<br />int fra[8];<br />int q[max][8], best[max], choose[max], pre[max], path[100];<br />bool vis[max], cov[9];<br />int head = 0, tail = 0, now[8];<br />int hash(int *a) {<br />int num = 0;<br />memset(cov,0,sizeof(cov));<br />for (int i = 0; i < 8; i++) {<br />for (int j = 1; j < a[i]; j++)<br />if (!cov[j]) num += fra[7-i];<br />cov[a[i]] = 1;<br />}<br />return num;<br />}<br />void check() {<br />int num = hash(now);<br />if (!vis[num]) {<br />tail++;<br />best[tail] = best[head]+1;<br />vis[num] = 1;<br />}<br />}<br />int main(){<br />freopen("msquare.in", "r", stdin);<br />freopen("msquare.out", "w", stdout);<br />fra[0] = 1;<br />for (int i = 1; i <= 7; i++) fra[i] = fra[i-1]*i;<br />for (int i = 0; i <= 7; i++) scanf("%d", &q[0][i]);<br />best[0] = 0;<br />memset(vis,0,sizeof(vis));<br />vis[0] = 1;<br />pre[0] = -1;<br />int final = hash(q[0]);<br />for (int i = 0 ; i <= 7; i++) q[0][i] = i+1;<br />//printf("%d/n", final);<br />if (final == 0) printf("0/n/n"); else//why???<br />while (head <= tail) {<br />for (int i = 0; i < 3; i++) {<br />for (int j = 0; j < 8; j++) now[j] = q[head][d[i][j]];<br />int num = hash(now);<br />if (!vis[num]) {<br />tail++;<br />vis[num] = true;<br />for (int j = 0; j < 8; j++) q[tail][j] = now[j];<br />best[tail] = best[head] + 1;<br />pre[tail] = head;<br />choose[tail] = i;<br />if (num == final) break;<br />}<br />}<br />if (vis[final]) {<br />int len = 0;<br />printf("%d/n", best[tail]);<br />while (tail != 0) {<br />len++;<br />path[len] = choose[tail];<br />tail = pre[tail];<br />}<br />for (int i = len; i > 0; i--) {<br />printf("%c", path[i]+'A');<br />len++;<br />if (len % 60 == 0 || i == 1) printf("/n");<br />}<br />}<br />head++;<br />}<br />return 0;<br />}<br />

 

題目六:Sweet Butter

演算法:SPFA

題目大意:給出一張圖,有一些人在某些點,求出最小的集合代價。

由於這張圖邊比較稀疏,用鄰接表存好,且訪問起來更方便;

用SPFA分別求出任意兩點間的最短路。

/*<br />ID: zhangji42<br />TASK: butter<br />LANG: C++<br />*/<br />#include <stdio.h><br />#include <string.h><br />const<br />int maxn = 801, maxcow = 501, maxedge = 1451*2;<br />int cow[maxcow], first[maxn];<br />int v[maxedge], w[maxedge], next[maxedge];<br />int q[maxedge*5], best[maxn], vis[maxn];<br />int main(){<br />freopen("butter.in", "r", stdin);<br />freopen("butter.out", "w", stdout);<br />int M, N, C;<br />scanf("%d %d %d", &M, &N, &C);<br />for (int i = 1; i <= M; i++) scanf("%d", &cow[i]);<br />memset(first,-1,sizeof(first));<br />int u;<br />for (int i = 1; i <= C; i++) {<br />scanf("%d %d %d", &u, &v[i], &w[i]);<br />next[i] = first[u];<br />first[u] = i;</p><p>v[C+i] = u;<br />w[C+i] = w[i];<br />next[C+i] = first[v[i]];<br />first[v[i]] = C+i;<br />}<br />int min = 1 << 30;<br />for (int i = 1; i <= N; i++) {<br />int head = 0, tail = 0, now;<br />q[head] = i;<br />memset(vis,0,sizeof(vis));<br />vis[i] = 1;<br />for (int j = 1; j <= N; j++) best[j] = 1 << 29;<br />best[i] = 0;<br />while (head <= tail) {<br />now = q[head];<br />for (int k = first[now]; k != -1; k = next[k])<br />if (best[now] + w[k] < best[v[k]]) {<br />best[v[k]] = best[now] + w[k];<br />if (!vis[v[k]]) {<br />q[++tail] = v[k];<br />vis[v[k]] = 1;<br />}<br />}<br />vis[now] = 0;<br />head++;<br />}<br />now = 0;<br />for (int j = 1; j <= M; j++) {now += best[cow[j]];}//printf("%d %d/n", cow[j], best[cow[j]]);}<br />if (now < min) min = now;<br />}<br />printf("%d/n", min);<br />return 0;<br />}<br />

 

很好,這一個星期的任務完成了,不過接下來還要奮戰學校的OJ啊!加油!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.