【牛客練習賽60 】A【按位推導公式】B【公式+逆元】C【子序列DP】D【暴力?】

題目連接

文章目錄

A

思路:公式推導就行了:
i=1nj=1n(ai&aj)=i=1nj=1nk=0302kaikajk=k=0302ki=1nj=1naikajk \sum_{i=1}^n\sum_{j=1}^n(a_i\&a_j) = \sum_{i=1}^n\sum_{j=1}^n\sum_{k=0}^{30}2^ka_{ik}a_{jk} = \sum_{k=0}^{30}2^k\sum_{i=1}^n\sum_{j=1}^na_{ik}a_{jk}
對於 aikajka_{ik}a_{jk} ,只有都是1才爲1,所以統計這n個值中第k個二進制位1的個數cnt[k],後面一串就可以表示爲 C(cnt[k], 2)。
=k=0302k(cnt[k](cnt[k]1)2) = \sum_{k=0}^{30}2^k (\frac{cnt[k] * (cnt[k]- 1)}{2})

Coding:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 1e5 + 11;
const int M = 1e6 + 11;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int cnt[31];
int main(int argc, char **args){
    int n;cin >>n;

    for(int i = 0; i < n ; i++){
        ll a; scanf("%lld", &a);
        for(int j = 30; j >= 0; j--){
            if(a >> j & 1) 
                cnt[j]++;
        }
    }

    ll sum = 0 ;
    for(int i = 30; i >= 0; i--){
        sum += (1 << i) * 1ll *(cnt[i] * 1ll * (cnt[i]) ); 
    }

    cout << sum <<"\n";
return 0;
}

B

思路:對於每條邊,它可以包括在n-2個三角形中,這樣算下來,是比答案多了一倍,除以2就行了,不過這裏是乘2的逆元。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 1e5 + 11;
const int M = 1e6 + 11;
const int MOD = 998244353;

ll _pow(ll a, ll b, ll c ){
    ll s =  1, base = a % c;
    while(b){
        if(b & 1) s = (s * base) % c;
        b >>= 1;
        base = base * base % c;
    }
    return s;
}

int main(int argc, char **args){ 
    int n; cin >> n;
    vector<ll> x(n + 1), y(n +  1);
    for(int i = 1; i <= n; i++){
        scanf("%lld%lld", &x[i], &y[i]);
    }

    ll sum = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n ;j ++){
            sum += (abs(x[i] - x[j]) + abs(y[i] - y[j])) % MOD * (n - 2) % MOD;
            sum %= MOD;
         }
    }

    cout << sum  * _pow(2, MOD - 2,  MOD)% MOD<<"\n";
return 0;
}

/*

4
0 0 
1 0
0 1
1 1

*/

C

問題:求長度爲n序列中,本質不同的長度爲k子序列有多少個。
思路:動態規劃,對於子序列的動態規劃,思路也很常見。這裏定義dp[i][j]dp[i][j] 表示截止到第 ii 個值,本質不同的長度爲 jj 的子序列個數。
51Nod 上有一個動態規劃,是求長度爲n序列中,本質不同的子序列有多少個。和這道題有異曲同工之妙。

Coding:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 1e3 + 11;
const int M = 1e6 + 11;
const int MOD = 1e9 + 7;

int dp[N][N], last[N]; // last[i] 表示到目前爲止,i 最後一次出現的位置。
char s[N];
int main(int argc, char **args){
    int n, k; cin >> n >> k;
    scanf("%s" , s + 1);
    int len = strlen(s + 1);
    for(int i = 0; i <= len; i++) dp[i][0] = 1;

    for(int i = 1; i <= len; i++){
        for(int j = 1; j <= k; j++){
            dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
            if(last[s[i]] ){ // 去重複元素
                dp[i][j] -= dp[last[s[i]] - 1][j - 1];
             }
            dp[i][j] = (dp[i][j] % MOD + MOD) % MOD;
        }
        last[s[i]] = i;
    }

    cout << dp[len][k] <<"\n";
return 0;
}

D

貌似用最暴力的方法都能夠過?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章