牛客挑战赛32

Contest Page

A

sol 真的有人不会做这道题?
#include<bits/stdc++.h>
using namespace std;
 
int main(){
    string s;
    int N; cin >> N;
    for(int i = 1 ; i <= N ; ++i){
        cin >> s;
        if(s.size() >= 2 && s[s.size() - 1] == 'K' && s[s.size() - 2] == 'A'){
            for(int i = 0 ; i < s.size() - 2 ; ++i)
                cout << s[i];
            return 0;
        }
    }
    return 0;
}

B

sol $114514$只有$8$个约数,暴力统计数量然后人脑枚举所有可行方案就行了。
#include<bits/stdc++.h>
using namespace std;
 
#define int unsigned long long
const int _ = 229029 , tar[] = {2,31,1847};
signed main(){
    int N; cin >> N; static int arr[_] , num[8];
    for(int i = 1 ; i <= N ; ++i){
        cin >> arr[i];
        if(arr[i] != 0)
            if(114514 % arr[i] == 0){
                int cur = 0;
                for(int j = 0 ; j < 3 ; ++j)
                    if(arr[i] % tar[j] == 0) cur |= 1 << j;
                  ++num[cur];
            }
    }
    int p = num[7] + num[6] * num[1] + num[5] * num[2] + num[3] * num[4] + num[1] * num[2] * num[4];
    cout << p * (1 + num[0]);
    return 0;
}

C

sol 把前几项算出来丢到OEIS里发现递推公式:$a_i=2a_{i-1}+a_{i-2}-2a_{i-3}-a_{i-4}$,然后矩乘就行了。
#include<bits/stdc++.h>
using namespace std;
 
#define int long long
const int MOD = 998244353;
struct matrix{
    int a[4][4];
    matrix(){memset(a , 0 , sizeof(a));}
    int* operator [](int x){return a[x];}
    matrix operator *(matrix b){
        matrix c;
        for(int i = 0 ; i < 4 ; ++i)
            for(int k = 0 ; k < 4 ; ++k)
                for(int j = 0 ; j < 4 ; ++j)
                    c[i][j] = (c[i][j] + a[i][k] * 1ll * b[k][j]) % MOD;
        return c;
    }
}G , T;
 
signed main(){
    int N; cin >> N;
    if(N == 1) puts("0");
    else if(N == 2) puts("1");
    else if(N == 3) puts("2");
    else if(N == 4) puts("5");
    else{
        T[1][0] = T[2][1] = T[3][2] = 1;
        T[3][3] = 2; T[2][3] = 1; T[1][3] = MOD - 2; T[0][3] = MOD - 1;
        N -= 4; G[0][0] = 0; G[0][1] = 1; G[0][2] = 2; G[0][3] = 5;
        while(N){
            if(N & 1) G = G * T;
            T = T * T; N >>= 1;
        }
        cout << G[0][3];
    }
    return 0;
}

D

sol 考虑枚举$1 \leq i$<$j \leq N$并$O(1)$计算方案数。设$p(x,y)$表示将$x$个数放到$x$个位置,其中$y$个数有限制某个位置不能放的方案数,设$S_i = \sum\limits_{j=1}^ij = \binom{i+1}{2}$。

枚举$i,j$放在了$p_i,p_j$中多少个位置:
如果放了两个位置,一定是$j$在$p_i$、$i$在$p_j$。如果这样会产生贡献,那么我们就用$|i-j||p_i-p_j|p(N-2,N-2)$贡献答案;
如果放了一个位置,考虑$j$在$p_i$、$i$在$p_j$两种情况的可行方案距离总和,有可能会出现$i$在$p_j$、$j$在$p_i$的情况减掉,得到可行方案距离总和$S$。我们就可以用$|i-j|Sp(N-2,N-3)$贡献答案。
如果一个位置都没有,就是总距离$\sum\limits_{i=1}^{N-1}S_i$减去上述两种方案的距离乘上$|i-j|$乘上$p(N-2,N-4)$贡献答案。

所以我们要算$p(N-2,N-2),p(N-2,N-3),p(N-2,N-4)$,直接容斥就行了。
#include<bits/stdc++.h>
using namespace std;
 
const int MOD = 998244353;
int num[1003][3] , N , T , p[1003] , jc[1003] , inv[1003] , sum1[1003] , sum2[1003];
 
int poww(long long a , int b){
    int times = 1;
    while(b){
        if(b & 1) times = times * a % MOD;
        a = a * a % MOD; b >>= 1;
    }
    return times;
}
 
int ch(int a , int b){return 1ll * jc[a] * inv[b] % MOD * inv[a - b] % MOD;}
 
int main(){
    jc[0] = 1;
    for(int i = 1 ; i <= 1000 ; ++i) jc[i] = 1ll * jc[i - 1] * i % MOD;
    inv[1000] = poww(jc[1000] , MOD - 2);
    for(int i = 999 ; i >= 0 ; --i) inv[i] = inv[i + 1] * (i + 1ll) % MOD;
    for(int i = 1 ; i <= 1000 ; ++i)
        for(int j = 0 ; j <= i && j <= 2 ; ++j){
            num[i][j] = 0;
            for(int k = 0 ; k <= i - j ; ++k)
                num[i][j] = (num[i][j] + (k & 1 ? MOD - 1ll : 1ll) * jc[i - k] % MOD * ch(i - j , k)) % MOD;
        }
    for(int i = 1 ; i <= 1000 ; ++i) sum1[i] = sum1[i - 1] + i;
    for(int i = 1 ; i <= 1000 ; ++i) sum2[i] = (sum2[i - 1] + sum1[i]) % MOD;
    for(cin >> T ; T ; --T){
        cin >> N; int sum = 0;
        for(int i = 1 ; i <= N ; ++i) cin >> p[i];
        if(N == 1){puts("0"); continue;}
        if(N == 2){printf("%d\n" , p[1] == 1 ? 1 : 0); continue;}
        for(int i = 1 ; i <= N ; ++i){
            for(int j = i + 1 ; j <= N ; ++j){
                int val = 0;
                val = (val + 1ll * num[N - 2][2] *
                       (sum2[N - 1] - (sum1[p[i] - 1] + sum1[N - p[i]]) - (sum1[p[j] - 1] + sum1[N - p[j]]) + abs(p[i] - p[j])) % MOD + MOD) % MOD;
                val = (val + 1ll * num[N - 2][1] * (sum1[N - p[i]] + sum1[p[j] - 1] - 2 * max(p[j] - p[i] , 0)) % MOD + MOD) % MOD;
                if(p[i] < p[j]) val = (val + 1ll * num[N - 2][0] * (p[j] - p[i])) % MOD;
                sum = (sum + 1ll * val * (j - i)) % MOD;
            }
        }
        cout << sum << endl;
    }
    return 0;
}

E

sol 考虑每一个点取正和取负对逆序对数量造成的影响。不难发现某个点取负可以使其子树中所有权值绝对值比它小的和它产生逆序对,而大于它的则一定由这个更大的点取正或者负来确定;它取正可以使其祖先中所有权值绝对值比它小的和它产生逆序对。

所以每个点取正取负对逆序对数量的贡献是独立的,不受其他节点的影响。

把两个的贡献一个二维数点、一个dfs的时候维护祖先权值进行计算,然后bitset优化背包就可以算出是否合法。
#include<bits/stdc++.h>
using namespace std;
 
int read(){int a; scanf("%d" , &a); return a;}
 
const int _ = 1e5 + 7;
vector < int > ch[_]; int N , ts , val[_] , lsh[_] , sum[_] , add[_][2] , dfn[_] , sz[_] , ind[_];
bitset < 30001 > now;
 
namespace BIT{
#define lowbit(x) ((x) & -(x))
    int arr[_];
    void add(int x , int n){while(x <= N){arr[x] += n; x += lowbit(x);}}
    int qry(int x){int sum = 0; while(x){sum += arr[x]; x -= lowbit(x);}return sum;}
}
 
void dfs(int x , int p){
    ind[dfn[x] = ++ts] = x; sz[x] = 1; add[x][0] = BIT::qry(val[x]); BIT::add(val[x] , 1);
    for(auto t : ch[x]) if(!sz[t]){dfs(t , x); sz[x] += sz[t];}
    BIT::add(val[x] , -1);
}
 
#define PII pair < int , int >
void calc(){
    vector < PII > qry;
    for(int i = 1 ; i <= N ; ++i){qry.push_back(PII(dfn[i] - 1 , -i)); qry.push_back(PII(dfn[i] + sz[i] - 1 , i));}
    sort(qry.begin() , qry.end()); int pos = 0;
    for(auto t : qry){
        while(pos < t.first) BIT::add(val[ind[++pos]] , 1);
        int flg = t.second < 0 ? -1 : 1 , id = abs(t.second);
        add[id][1] += flg * BIT::qry(val[id]);
    }
}
 
int main(){
    N = read(); for(int i = 1 ; i <= N ; ++i) val[i] = lsh[i] = read();
    sort(lsh + 1 , lsh + N + 1);
    for(int i = 1 ; i <= N ; ++i) val[i] = lower_bound(lsh + 1 , lsh + N + 1 , val[i]) - lsh;
    for(int i = 1 ; i < N ; ++i){
        int p = read() , q = read();
        ch[p].push_back(q); ch[q].push_back(p);
    }
    dfs(1 , 0); calc(); now[0] = 1;
     
    for(int i = 1 ; i <= N ; ++i){bitset < 30001 > p = now , q = now; p <<= add[i][0]; q <<= --add[i][1]; now = p | q;}
    for(int Q = read() ; Q ; --Q) puts(now[read()] ? "Orz" : "QAQ");
    return 0;
}

F

传送门

posted @ 2019-09-20 22:43  cjoier_Itst  阅读(448)  评论(0编辑  收藏  举报