某模拟题题解 2016.11.15
二叉树是一个幌子,其实中序遍历后变成数列。
原问题变成了给定一个数列,问最少把多少个数修改为其他整数,使得数列递增。
考察修改后要满足的条件($b$数组为中序遍历后得到的数组),即
$b_{i}\leqslant b_{i + 1} - 1$
所以有:
$b_{i} - i\leqslant b_{i + 1} -\left ( i + 1 \right )$
设$c_{i} = b_{i} - i$,那么求它的最长不下降子序列的长度就是不用修改的数的个数的最大值,用$n$减去它即可得到答案。
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cctype> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 #include<fstream> 8 #include<sstream> 9 #include<algorithm> 10 #include<map> 11 #include<set> 12 #include<queue> 13 #include<vector> 14 #include<stack> 15 using namespace std; 16 typedef bool boolean; 17 #define INF 0xfffffff 18 #define smin(a, b) a = min(a, b) 19 #define smax(a, b) a = max(a, b) 20 template<typename T> 21 inline void readInteger(T& u){ 22 char x; 23 int aFlag = 1; 24 while(!isdigit((x = getchar())) && x != '-'); 25 if(x == '-'){ 26 x = getchar(); 27 aFlag = -1; 28 } 29 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 30 ungetc(x, stdin); 31 u *= aFlag; 32 } 33 34 typedef class TreeNode{ 35 public: 36 int next[2]; 37 int val; 38 TreeNode(){ 39 next[0] = next[1] = 0; 40 } 41 }TreeNode; 42 43 template<typename T> 44 class IndexedStack{ 45 public: 46 T *p; 47 int s; 48 IndexedStack():s(0), p(NULL){ } 49 IndexedStack(int size):s(0){ 50 p = new T[(const int)size]; 51 } 52 boolean empty() { return s == 0; } 53 T top() { return p[s - 1]; } 54 void pop() { s--; } 55 void push(T& x) { p[s++] = x; } 56 void clear() { s = 0; } 57 int size() { return s; } 58 T& operator [](int pos) { return p[pos]; } 59 }; 60 61 inline int lower_bound(int* a, int from, int end, int val){ 62 int l = from, r = end - 1; 63 while(l <= r){ 64 int mid = (l + r) >> 1; 65 if(a[mid] > val) r = mid - 1; 66 else l = mid + 1; 67 } 68 return r + 1; 69 } 70 71 int n; 72 int *a; 73 TreeNode* tree; 74 75 inline void init(){ 76 readInteger(n); 77 tree = new TreeNode[(const int)(n + 1)]; 78 for(int i = 1; i <= n; i++){ 79 readInteger(tree[i].val); 80 } 81 for(int i = 2, a, b; i <= n; i++){ 82 readInteger(a); 83 readInteger(b); 84 tree[a].next[b] = i; 85 } 86 } 87 88 IndexedStack<int> s; 89 inline int lis(){ 90 s = IndexedStack<int>(n); 91 for(int i = 1; i <= n; i++){ 92 if(s.empty() || a[i] >= s.top()){ 93 s.push(a[i]); 94 }else{ 95 int x = lower_bound(s.p, 0, s.size(), a[i]); 96 s[x] = a[i]; 97 } 98 } 99 return s.size(); 100 } 101 102 int cv; 103 void inorder(int node){ 104 if(tree[node].next[0]) inorder(tree[node].next[0]); 105 a[++cv] = tree[node].val - cv; 106 if(tree[node].next[1]) inorder(tree[node].next[1]); 107 } 108 109 inline void solve(){ 110 a = new int[(const int)(n + 1)]; 111 inorder(1); 112 int l = lis(); 113 printf("%d", n - l); 114 } 115 116 int main(){ 117 freopen("tree.in", "r", stdin); 118 freopen("tree.out", "w", stdout); 119 init(); 120 solve(); 121 return 0; 122 }
这道题算是一道很神奇的数论题吧。可以转化成图论(模最小的长度,然后跑最短路)来做,只不过有一个比较简单的方法,重点在于如何判断
大概分为下面三种情况
- 当所有的长度的最大公约数不为1时,一定不存在最大的不能修建的长度
- 当最小的一段为1时,也不存在(因为就没有不能围成的长度(len > 0)(如果木头足够的话))
- 当有一段长度为最小的那一段的长度都是可以围成的,那么刚刚找到的最大的不能的就是所求答案
Code
#include<iostream> #include<cstdio> #include<cctype> #include<cstring> #include<cstdlib> #include<cmath> #include<fstream> #include<sstream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #include<stack> using namespace std; typedef bool boolean; #define INF 0xfffffff #define smin(a, b) a = min(a, b) #define smax(a, b) a = max(a, b) template<typename T> inline void readInteger(T& u){ char x; int aFlag = 1; while(!isdigit((x = getchar())) && x != '-'); if(x == '-'){ x = getchar(); aFlag = -1; } for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); ungetc(x, stdin); u *= aFlag; } template<typename T> T gcd(T a, T b){ if(b == 0) return a; return gcd(b, a % b); } int n, m; int *a; int cl; boolean visited[3001]; boolean f[5000000]; int lis[3001]; inline void init(){ readInteger(n); readInteger(m); a = new int[(const int)(n + 1)]; for(int i = 1; i <= n; i++){ readInteger(a[i]); } } inline void getList(){ for(int i = 1; i <= n; i++){ int j = m; visited[a[i]] = true; while(j && a[i]){ visited[--a[i]] = true; j--; } } for(int i = 1; i <= 3000; i++){ if(visited[i]){ lis[++cl] = i; } } } inline void solve(){ if(lis[1] == 1){ printf("-1"); return; } int temp = lis[1]; for(int i = 2; i <= cl; i++) temp = gcd(temp, lis[i]); if(temp != 1){ printf("-1"); return; } f[0] = true; int last = 0; int maxv = -1; for(int i = 1; i < 5000000; i++){ for(int j = 1; j <= cl; j++){ if(lis[j] > i) continue; if(f[i - lis[j]]){ f[i] = true; break; } } if(!f[i]){ last = 0; maxv = i; }else last++; if(last == lis[1]){ printf("%d", maxv); return; } } printf("-1"); } int main(){ freopen("bullpen.in", "r", stdin); freopen("bullpen.out", "w", stdout); init(); getList(); solve(); return 0; }
仔细分析一下,很快你就会推出一个式子
再拿几个展开式来看看,对照着看,然后再一列一列地看,你会高兴地发现这是一个等比数列
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cctype> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 #include<fstream> 8 #include<sstream> 9 #include<algorithm> 10 #include<map> 11 #include<set> 12 #include<queue> 13 #include<vector> 14 #include<stack> 15 using namespace std; 16 typedef bool boolean; 17 #define INF 0xfffffff 18 #define smin(a, b) a = min(a, b) 19 #define smax(a, b) a = max(a, b) 20 template<typename T> 21 inline void readInteger(T& u){ 22 char x; 23 int aFlag = 1; 24 while(!isdigit((x = getchar())) && x != '-'); 25 if(x == '-'){ 26 x = getchar(); 27 aFlag = -1; 28 } 29 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 30 ungetc(x, stdin); 31 u *= aFlag; 32 } 33 34 template<typename T> 35 inline void putInteger(T u){ 36 if(u == 0){ 37 putchar('0'); 38 return; 39 } 40 if(u < 0){ 41 putchar('-'); 42 u *= -1; 43 } 44 stack<char> s; 45 while(u != 0) s.push(u % 10 + '0'), u /= 10; 46 while(!s.empty()) putchar(s.top()), s.pop(); 47 } 48 49 const int moder = 1234567891; 50 51 long long _pow(long long x, int pos){ 52 if(x == 1) return 1; 53 if(pos == 1) return x; 54 long long temp = _pow(x, pos / 2); 55 if(pos & 1) return temp * temp % moder * x % moder; 56 return temp * temp % moder; 57 } 58 59 int T; 60 int n, k; 61 62 long long C[32][32]; 63 64 inline void init_c(){ 65 C[0][0] = 1; 66 for(int i = 1; i <= 31; i++){ 67 for(int j = 1; j <= i; j++){ 68 C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; 69 } 70 } 71 } 72 73 inline void init(){ 74 readInteger(n); 75 readInteger(k); 76 } 77 78 inline void solve(){ 79 int sign = 1; 80 long long result = 0, inv; 81 for(int i = k; i >= 1; i--){ 82 long long a1 = i; 83 long long an = _pow(i, n); 84 if(i == 1){ //最后一项 85 (result += sign * ((n * C[k + 1][k]) % moder) + moder) %= moder; 86 }else{ 87 inv = _pow(i - 1, moder - 2); 88 (result += sign * ((an * i % moder - a1 + moder) % moder * inv % moder * C[k + 1][k - i + 1]) + moder) %= moder; 89 } 90 sign *= -1; 91 } 92 putInteger(result); 93 putchar('\n'); 94 } 95 96 int main(){ 97 freopen("pearl.in", "r", stdin); 98 freopen("pearl.out", "w", stdout); 99 init_c(); 100 readInteger(T); 101 while(T--){ 102 init(); 103 solve(); 104 } 105 return 0; 106 }