首页 > 其他 > 详细

BestCoder #58 div1

时间:2015-10-08 21:16:40      阅读:237      评论:0      收藏:0      [点我收藏+]

2015-10-08 19:14:54

总结:赛后补的一场。题目蛮有意思的。

 

A:DFS

思路:搜一下几个环然后判断一下即可。

技术分享
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define MP(a,b) make_pair(a,b)
#define PB push_back

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 100010;

int T;
int n,ans,cnt;
int A[MAXN],B[MAXN],pos[MAXN];
int vis[MAXN];

void Dfs(int p){
    if(vis[p]) return;
    cnt++;
    vis[p] = 1;
    Dfs(pos[p]);
}

int main(){
    scanf("%d",&T);
    while(T--){
        MEM(vis,0);
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i) scanf("%d",A + i);
        for(int i = 1; i <= n; ++i){
            int a;
            scanf("%d",&a);
            B[A[i]] = a;
            pos[a] = A[i];
        }
        ans = 0;
        for(int i = 1; i <= n; ++i) if(vis[i] == 0){
            cnt = 0;
            Dfs(i);
            if(cnt == 1) ans++;
            else ans += cnt - 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

B:DP

题意:给出n个数,算出所有子序列去掉连续相同数(只保留一个)后的总和。

思路:总的思路就是总数 - 重复的计数。我们可以枚举每个数,算出其贡献,比如对于第i个数vi。先算左边的数,可取可不取,但是与vi相同的数一定不取,方案数为L,同理算出右边的方案数(算右边时可以取与vi相同的数),那么贡献就是vi×L×R。

技术分享
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define MP(a,b) make_pair(a,b)
#define PB push_back

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 100010;
const ll mod = 1e9 + 7;

int T;
int n,A[MAXN];
ll pw[MAXN],pre[MAXN],val[MAXN];
map<int,ll> S1;

int main(){
    pw[0] = pre[0] = 1;
    for(int i = 1; i <= 100000; ++i){
        pw[i] = pw[i - 1] * 2LL % mod;
        pre[i] = (pre[i - 1] + pw[i]) % mod;
    }
    scanf("%d",&T);
    while(T--){
        S1.clear();
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i)
            scanf("%d",A + i);
        for(int i = 1; i <= n; ++i){
            if(i == 1) val[i] = 1;
            else val[i] = (1 + pre[i - 2] - S1[A[i]]) % mod;
            val[i] = (val[i] + mod) % mod;
            S1[A[i]] += pw[i - 1];
        }
        for(int i = n - 1; i >= 1; --i){
            val[i] = (val[i] * (1 + pre[n - i - 1])) % mod;
        }
        ll ans = 0;
        for(int i = 1; i <= n; ++i){
            ans = (ans + A[i] * val[i] % mod) % mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

C:树状数组

题意:n个数删除连续的m个数,算出最小逆序数。

思路:用两个树状数组模拟一个删除框即可。

技术分享
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define MP(a,b) make_pair(a,b)
#define PB push_back

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 100010;

int T,n,m;
int A[MAXN],fk[2][MAXN];

void Update(int id,int x,int d){
    while(x <= n){
        fk[id][x] += d;
        x += x & (-x);
    }
}

int Getsum(int id,int x){
    int res = 0;
    while(x){
        res += fk[id][x];
        x -= x & (-x);
    }
    return res;
}

int main(){
    scanf("%d",&T);
    while(T--){
        MEM(fk,0);
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; ++i) scanf("%d",A + i);
        ll inv = 0;
        for(int i = m + 1; i <= n; ++i){
            inv += (i - m - 1) - Getsum(1,A[i]);
            Update(1,A[i],1);
        }
        ll ans = inv;
        // fk0 : pre , fk1 : suf
        for(int i = 1; i + m <= n; ++i){
            inv -= (i - 1) - Getsum(0,A[i + m]);
            inv -= Getsum(1,A[i + m] - 1);
            Update(1,A[i + m],-1);
            inv += (i - 1) - Getsum(0,A[i]);
            inv += Getsum(1,A[i] - 1);
            Update(0,A[i],1);
            ans = min(ans,inv);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

D:DP+矩阵快速幂+生成树计数

思路:q轮选出n-1条边(构成一棵树)的方案数为cnt。对于每个生成树,构成其的方案数都是cnt。用dp[i][j]表示i轮选了j种边的方案数,转移方程:dp[i][j] = dp[i - 1][j - 1] * (n - j) + dp[i - 1][j] * j 用矩阵快速幂算出cnt。下面就是生成树计数,算出生成树种类num,那么答案就是cnt × num。

技术分享
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define MP(a,b) make_pair(a,b)
#define PB push_back

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 110;

int T,n,m,p,q,mod;
int D[MAXN][MAXN],G[MAXN][MAXN];

ll Det(int n){
    ll A[MAXN][MAXN];
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            A[i][j] = D[i][j];
    ll res = 1;
    for(int i = 1; i <= n; ++i){
        for(int j = i + 1; j <= n; ++j){
            while(A[j][i]){
                ll t = A[i][i] / A[j][i];
                 for(int k = i; k <= n; ++k)
                     A[i][k] = (A[i][k] - A[j][k] * t) % mod;
                 for(int k = i; k <= n; ++k)
                     swap(A[i][k],A[j][k]);
                 res = -res;
            }
        }
        if(!A[i][i]) return 0;
        res = res * A[i][i] % mod;
    }
    return (res + mod) % mod;
}

struct Mx{
    ll a[MAXN][MAXN];
    void clear(){ MEM(a,0); }
    void stand(){ clear(); for(int i = 1; i <= n; ++i) a[i][i] = 1; }
    Mx operator * (const Mx &b){
        Mx c; c.clear();
        for(int k = 1; k <= n; ++k)
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j){
            c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j]) % mod;
        }
        return c;
    }
};

Mx t;

Mx Q_pow(int v){
    Mx res; res.stand();
    while(v){
        if(v & 1) res = res * t;
        t = t * t;
        v >>= 1;
    }
    return res;
}

int main(){
    scanf("%d",&T);
    while(T--){
        MEM(D,0);
        MEM(G,0);
        scanf("%d%d%d%d",&n,&m,&p,&q);
        mod = p;
        for(int i = 1; i <= m; ++i){
            int a,b;
            scanf("%d%d",&a,&b);
            D[a][a]++;
            D[b][b]++;
            G[a][b] = G[b][a] = 1;
        }
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                D[i][j] -= G[i][j];
        ll val = Det(n - 1);
        //structure Mx t
        t.clear();
        for(int i = 1; i <= n; ++i){
            t.a[i][i] = i;
            t.a[i][i - 1] = n - i;
        }
        Mx ans; ans.clear();
        ans.a[1][1] = n - 1;
        ans = Q_pow(q - 1) * ans;
        printf("%lld\n",(val * ans.a[n - 1][1]) % mod);
    }
    return 0;
}
View Code

 

BestCoder #58 div1

原文:http://www.cnblogs.com/naturepengchen/p/4862132.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!