標籤:
題目連結:點擊開啟連結
A:
#include <cstdio>#include <vector>#include <algorithm>#include <iostream>#include <map>#include <set>#include <queue>#include <cstring>#include <cmath>#include <string>using namespace std;int a[12][11];int main() { for (int i = 0; i <= 10; ++i) a[i][0] = a[0][i] = 1; for (int i = 1; i <= 10; ++i) { for (int j = 1; j <= 10; ++j) { a[i][j] = a[i - 1][j] + a[i][j - 1]; } } int n; scanf("%d", &n); printf("%d\n", a[n - 1][n - 1]); return 0;}
B:構造
#include <cstdio>#include <vector>#include <algorithm>#include <iostream>#include <map>#include <set>#include <queue>#include <cstring>#include <cmath>#include <string>using namespace std;typedef long long ll;const int N = 105;int n, m;int a[N];int main() { while (~scanf("%d %d", &n, &m)){ int mi = 1000, mx = 0; for (int i = 1; i <= n; i++){ scanf("%d", &a[i]); mi = min(mi, a[i]); mx = max(mx, a[i]); } if (mx - mi > m)puts("NO"); else { puts("YES"); for (int i = 1; i <= n; i++){ for (int j = 1; j <= mi; j++)printf("%d ", 1); a[i] -= mi; for (int j = 1; j <= a[i]; j++)printf("%d ", j); puts(""); } } } return 0;}
C:類比
題意:有一個n長的嚴格單調遞增序列,對於序列上某個點的權值就是數位和(即 123的數位和為6)
現在給出這個序列的數位和,構造一個序列使得最後一個數最小。
略麻煩,首先我們得到一個結論:對於給定的sum[i],我們目標是構造最小的且比前面的數大的數。
一定是構造最小的數,因為大的數我們也能用sum[i]構造,倒不如構造最小的。
構造時先判斷是否需要進位(即位元能不能和上一個數字一樣)
然後暴力遞增即可。
#include <cstdio>#include <vector>#include <algorithm>#include <iostream>#include <map>#include <set>#include <queue>#include <cstring>#include <cmath>#include <string>using namespace std;typedef long long ll;const int N = 305;int n;int Ni(vector<int>&x){//返回最低位且不為9的位置,若全為9返回-1 for (int i = 0; i < x.size(); i++)if (x[i] != 9)return i; return -1;}void add(vector<int>&x){//讓x的數位和增加1 int ni = Ni(x); if (ni == -1){//全為9時想要讓數位和增加1隻能在最高位添一個1 x.push_back(1); } else { x[ni]++; }}void hehe(vector<int>&now, vector<int>&old, int sum, int l){//當位元比上一個數字要大時,我們先構造一個100···這樣的序列,且使得這個序列位元最少且全為9時的數位和>=sum,然後暴力增加數位和即可 int dig = old.size() + 1; while (dig * 9 < sum){ dig++; } dig--; now.clear(); while (dig--)now.push_back(0); now.push_back(1); sum--; while (sum--)add(now);}void work(vector<int>&now, vector<int>&old, int sum,int l){ if (l < sum){//如果數位和已經比上一個數大就直接從上一個數開始增加數位和 now = old; sum -= l; while (sum--)add(now); return; } else { if (Ni(old) == -1 || old.size() * 9 < sum){ hehe(now, old, sum, l); return; } now = old; int s = 0; int find = -1; for (int i = now.size()-1; i >= 0; i--){//如果我們把上一個數的某一位 find 增加1,然後把個位到find位全變0,能使得數位和<=sum 那麼我們就不必增加位元,否則還是要增加位元 s += now[i]; if (now[i] < 9 && s + 1 <= sum){ find = i; } } if (find!=-1){ now[find]++; for (int i = 0; i < find; i++)now[i] = 0; int ssum = sum; for (int i = 0; i < now.size(); i++)ssum -= now[i]; if (ssum >= 0){ while (ssum--){ add(now); } for (int i = now.size() - 1; i >= 0; i--)if (now[i]>old[i]) return; else if (now[i] < old[i])break; } } hehe(now, old, sum, l); }}vector<int>u[2];int main() { while (~scanf("%d", &n)){ u[0].clear(); u[1].clear(); u[1].push_back(0); int cur = 0, last = 1; int sum, l = 0; while (n--){ scanf("%d", &sum); work(u[cur], u[last], sum, l); for (int i = u[cur].size() - 1; i >= 0; i--)putchar('0' + u[cur][i]); puts(""); l = sum; cur ^= 1; last ^= 1; } } return 0;}/*5111116*/
D:
還不會,
E:
#include <cstdio>#include <vector>#include <algorithm>#include <iostream>#include <map>#include <set>#include <queue>#include <cstring>#include <cmath>#include <string>using namespace std;const int MAX_N = 500007;int bit[MAX_N << 1], len;int sum(int i) { int s = 0; while (i > 0) { s += bit[i]; i -= i & -i; } return s;}void add(int i, int x) { while (i <= len) { bit[i] += x; i += i & -i; }}char str[MAX_N];bool is(char ch) { return ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U' || ch == 'Y';}long long z[MAX_N];long long zz[MAX_N];int main() { scanf("%s", str + 1); len = strlen(str + 1); for (int i = 1; str[i]; ++i) { if (is(str[i])) z[i] = z[i - 1] + 1; else z[i] = z[i - 1]; } for (int i = 1; i <= len; ++i) { zz[i] = zz[i - 1] + z[i]; } double ans = 0; for (int i = 0; i <= len; ++i) { if (len - (i + 1) >= 0) ans += (zz[len] - zz[len - (i + 1)] - (zz[i])) * 1. / (i + 1); } printf("%f\n", ans); return 0;}
F:dp[l][r]表示 區間[l,r] 構成一棵樹的方法數。
對於一個區間[l, r] 構成一棵樹,則點l一定是根,然後枚舉2個區間相乘即可
dp[l][r] = dp[l+1][i] * dp[i+1][r] ( i = [l+1, r] )
當然 a[i+1] > a[l+1] ,這樣才會滿足題目中的暴力代碼。。==
import java.io.PrintWriter;import java.text.DecimalFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.Map;import java.util.PriorityQueue;import java.util.Scanner;import java.util.Stack;import java.util.TreeMap;import java.util.TreeSet;import java.util.Queue;public class Main {int n;int[] a = new int[N];long[][] dp = new long[N][N];long dfs(int l, int r){if(dp[l][r] != -1)return dp[l][r];if(l >= r)return dp[l][r] = 1;long ans = 0;for(int i = l+1; i <= r; i++)if(i == r || a[i + 1] > a[l + 1])ans = (dfs(l+1, i) * dfs(i, r)+ans)%mod;return dp[l][r] = ans;}void work() {while(cin.hasNext()){n = cin.nextInt(); for(int i = 1; i <= n; i++)a[i] = cin.nextInt();for(int i = 1; i <= n; i++){for(int j = i; j <= n; j++)dp[i][j] = -1;}System.out.println(dfs(1, n));}}Main() {cin = new Scanner(System.in);out = new PrintWriter(System.out);}public static void main(String[] args) {Main e = new Main();e.work();out.close(); }public Scanner cin;public static PrintWriter out;static int N = 505;DecimalFormat df=new DecimalFormat("0.0000");static int mod = 1000000007 ;}
Tutorial CodeForces Round 289 (Div.2) (Second Winter Computer Camp Selection 2015) 題解