20200328题解

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;
}
View Code

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;
}
View Code

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;
}
View Code

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;
}
View Code

相关推荐