T1 纯模拟,额外维护每个工件最后的建造时间即可。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; inline long long read(){ long long ans = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) f *= (ch == '-') ? -1 : 1, ch = getchar(); do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar(); while(isdigit(ch)); return ans * f; } const int MAXN = 21, MAXT = MAXN*MAXN*MAXN; int num[MAXN*MAXN], bel[MAXN][MAXN], cost[MAXN][MAXN], last[MAXN], isWork[MAXN][MAXT], cnt[MAXN]; int main(){ int m = read(), n = read(); for(int i=1; i<=m*n; i++) num[i] = read(); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) bel[i][j] = read(); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) cost[i][j] = read(); for(int i=1; i<=n*m; i++){ cnt[num[i]]++; for(int t=last[num[i]]+1, sum=0; t<=MAXT; t++){ if(!isWork[bel[num[i]][cnt[num[i]]]][t]) sum++; else sum = 0; if(sum == cost[num[i]][cnt[num[i]]]){ for(int j=t-sum+1; j<=t; j++) isWork[bel[num[i]][cnt[num[i]]]][j] = true; last[num[i]] = t; break; } } } int ans = 0; for(int i=1; i<=n; i++) ans = max(ans, last[i]); printf("%d", ans); return 0; }
T2 答案可以在$O(n^2)$的时间内解决,其中一维枚举r的位长$len$,另一维枚举r的最高位的数字$lim$(这样就轻松解决了它给我们的限制)
设一位的最大值为$size$,最后答案相当于将$size$个数中大于$lim$的数中选出$len-1$个数按照升序进行排列,即$C_{size-lim}^{len-1}$,最后注意高精度即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; inline long long read(){ long long ans = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) f *= (ch == '-') ? -1 : 1, ch = getchar(); do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar(); while(isdigit(ch)); return ans * f; } const int MAXN = 600; const int BITLEN = 10000, BIGSIZE = 53; struct Big{ int val[BIGSIZE], len; void operator = (int x){ memset(val, 0, sizeof(val)); len = 1, val[1] = x; } Big(int x = 0){this->operator = (x);} Big operator + (Big x){ Big ans; ans.len = max(len, x.len) + 1; ans.len = max(ans.len, BIGSIZE - 2); for(int i=1; i<=ans.len; i++){ ans.val[i] += val[i] + x.val[i]; ans.val[i + 1] += ans.val[i] / BITLEN; ans.val[i] %= BITLEN; } while(ans.len > 1 && ans.val[ans.len] == 0) ans.len--; return ans; } void print(){ for(int i=len; i>=1; i--){ if(i != len) for(int j=BITLEN/10; j>1; j/=10) if(val[i] < j) putchar('0'); printf("%d", val[i]); } } }; Big C[MAXN][MAXN]; int main(){ int q = read(), w = read(); int n = w / q, lim = (1 << (w % q)) - 1, size = (1 << q) - 1; if(lim) n++; else lim = size; Big ans = 0; for(int i=0; i<=size+1; i++) for(int j=0; j<=i; j++) C[i][j] = (j == 0 || i == j) ? 1 : C[i-1][j-1] + C[i-1][j]; for(int len=2; len<=n; len++){ int temp = (len == n) ? lim : size; for(int i=1; i<=temp && size-i>=len-1; i++) ans = ans + C[size-i][len-1]; } ans.print(); return 0; }
T3 Dp[k][i][j]表示两次选择分别选到的纵坐标为i和j,一共进行k步的最大值,转移方程有四块,对应着两个点的左边和右边走来,值得注意的是:for循环内要判断计算出来的x坐标是否超出边界,否则需要将空间开到原来的两倍。其次最后的一步其实没有走到,答案输出最后一个的左边和上面即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; inline long long read(){ long long ans = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) f *= (ch == '-') ? -1 : 1, ch = getchar(); do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar(); while(isdigit(ch)); return ans * f; } const int MAXN = 101; int a[MAXN][MAXN], Dp[MAXN<<1][MAXN][MAXN]; int main(){ int n = read(), m = read(); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) a[i][j] = read(); for(int k=2; k<=m+n-2; k++) for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) Dp[k][i][j] = a[i][k-i+1] + a[j][k-j+1] + max(max(Dp[k-1][i][j], Dp[k-1][i-1][j-1]), max(Dp[k-1][i-1][j], Dp[k-1][i][j-1])); printf("%d", Dp[m+n-2][n-1][n]); return 0; }
T4 对于$i<j<k$,且$a_k<a_i<a_j$来说,将$i,j$放到同一个栈是不合法的,枚举每一对不合法的元素,判断是否为二分图,若不是则无法排序,否则直接染色后模拟,按照字典序先后输出结果即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; inline long long read(){ long long ans = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) f *= (ch == '-') ? -1 : 1, ch = getchar(); do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar(); while(isdigit(ch)); return ans * f; } const int MAXN = 1005; int head[MAXN], next[MAXN*MAXN], last[MAXN*MAXN], lineNum; void add(int x,int y){ lineNum++, next[lineNum] = head[x], last[lineNum] = y, head[x] = lineNum; } int a[MAXN], suf[MAXN], col[MAXN]; void DFS(int x,int pre){ col[x] = 3 - col[pre]; for(int l=head[x]; l; l=next[l]){ int y = last[l]; if(!col[y]) DFS(y, x); if(col[y] == col[x]){ printf("0"); exit(0); } } } int st1[MAXN], st2[MAXN], ans[MAXN<<1]; int main(){ int n = read(); for(int i=1; i<=n; i++) a[i] = read(); suf[n+1] = 1e9; for(int i=n; i>=1; i--) suf[i] = min(suf[i+1], a[i]); for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) if(a[i] < a[j] && suf[j+1] < a[i]) add(i, j), add(j, i); col[0] = 2; for(int i=1; i<=n; i++) if(!col[i]) DFS(i, 0); for(int i=1, now=1; i<=n; i++){ if(col[i] == 1) ans[++ans[0]] = 'a', st1[++st1[0]] = a[i]; else ans[++ans[0]] = 'c', st2[++st2[0]] = a[i]; while((st1[0] && st1[st1[0]] == now) || (st2[0] && st2[st2[0]] == now)){ if(st1[st1[0]] == now) ans[++ans[0]] = 'b', st1[0]--, now++; if(st2[st2[0]] == now) ans[++ans[0]] = 'd', st2[0]--, now++; } } putchar(ans[1]); for(int i=2; i<=ans[0]; i++) putchar(' '), putchar(ans[i]); return 0; }