牛客网暑期ACM多校训练营(第一场)

牛客网暑期ACM多校训练营(第一场)


A. Monotonic Matrix

考虑0和1的分界线,1和2的分界线,发现问题可以转化为两条不互相穿过的路径的方案数(可重叠),题解的做法就是把一条路径斜着平移,然后就转化为不可重叠了。现在考虑,如何计算从(0,0)道(n,m)不相交不可重叠的方案数,一条从(0,1)出发到达(n-1,m),一条从(1,0)出发到达(n,m-1),将他们乘起来的结果还包含相交的情况,于是再减去从(0,1)到(n,m-1)与(1,0)到(n-1,m)的方案数。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define MP make_pair
#define fr first
#define sc second
typedef long long ll;
const int N = 1e5 + 7;
const ll mod = 1e9 + 7;
using namespace std;
ll n,m,CC[2005][2005];
ll C(int n,int m) {return CC[n][m];}
int main() {
    rep(i,0,2003) CC[i][i]=CC[i][0]=1;
    rep(i,2,2003)rep(j,1,i) CC[i][j] = (CC[i-1][j]+CC[i-1][j-1])%mod;
    while(scanf("%lld%lld",&n,&m)!=EOF) {
        ll ans = ((C(n+m,m)*C(n+m,m))%mod - (C(n+m,m+1)*C(n+m,n+1))%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

B. Symmetric Matrix

关键在于把这个矩阵,考虑成一个邻接矩阵,然后发现一个每个点有两条边,且无自环,可以有重边。这张图实际上就是,每个点都属于唯一的一个环,环的大小大于等于2。求这种图的方案数。好像第一类斯特灵数?还得递推搞一下。详见:大佬的推导

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
const int N = 1e5 + 7;
using namespace std;
ll dp[N],n,m;
int main() {
    dp[1] = 0, dp[2] = 1, dp[3] = 1, dp[4] = 6;
    while(scanf("%lld%lld",&n,&m)!=EOF) {
        if(n<=4) {
            printf("%lld\n",dp[n]%m);
        }
        else {
            ll M;
            rep(i,5,n)
                M = 1LL*(i-1LL)*(i-2LL)/2LL,M%=m,
                dp[i] = (((((i-1)*dp[i-1])%m + ((i-1)*dp[i-2])%m)%m) - (M*dp[i-3])%m + m)%m;
            printf("%lld\n",dp[n]);
        }
    }
    return 0;
}

D. Two Graphs

\(n!\) 枚举与 \(G1\) 同构的图,在 \(G2\) 中找到相应的边,如果 \(m1\) 条边都可以匹配到,则将这种方案中用到的边压成一个64位二进制数,放到set里去重。另一种思路是,出现重算的情况就是,这个同构的图与自身的图相同,即使用这些点的映射,形成的新图与原图一致,这种自同构的情况要从答案中除去。

#include <bits/stdc++.h>
typedef unsigned long long ll;
const ll seed = 31;
const ll mod = 1e9 + 7;
inline int read() {
    char c = getchar();int x=0, f=1;
    while(c<'0'||c>'9'){if(c=='-')f = -1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
using namespace std;
int n,m1,m2,g[11][11],PH[11];
pair<int,int> p[1111];
int main() {
    while(scanf("%d%d%d",&n,&m1,&m2)!=EOF) {
        set<int> s;s.clear();
        memset(g,0,sizeof(g));
        for(int i=1;i<=m1;++i) {
            int u=read(),v=read();
            g[u][v] = g[v][u] = 1;
        }
        for(int i=1;i<=m2;++i) {
            int u=read(),v=read();
            p[i] = make_pair(u,v);
        }
        for(int i=1;i<=n;++i) PH[i]=i;
        do{
            ll hs=0,cnt=0;
            for(ll i=1;i<=m2;++i){
                if(g[PH[p[i].first]][PH[p[i].second]]) {
                    hs |= ((ll)1<<(i-(ll)1));
                    ++cnt;
                }
            }
            if(cnt == m1)s.insert(hs);
        }while(next_permutation(PH+1,PH+1+n));
        printf("%d\n",(int)s.size());
    }
    return 0;
}


J. Different Integers

先写了分块莫队tle,然后写了曼哈顿mst莫队tle,然后分块乱狗tle,t到终场。结束后,加了个快读,分块莫队ac..。还有其他一些做法,其实把整个序列在后边复制一份,不就变成了单个区间询问数字种类的模板题了。(让快读成为习惯。。。为何泥萌常数辣么小

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define MP make_pair
#define fr first
#define sc second
typedef long long ll;
const int N = 1e5 + 7;
inline int read() {
    char c = getchar();int x=0, f=1;
    while(c<'0'||c>'9'){if(c=='-')f = -1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
using namespace std;
int n,q,a[N];
struct pp{int l,r,id,ans;}Q[N];
int B,belong[N];
void build() {
    B = sqrt(n);
    for(int i=1; i<=n; i++) belong[i] = (i-1)/B + 1;
}
bool cmp(pp a, pp b) {
    if(belong[a.l] == belong[b.l]) return a.r < b.r;
    return belong[a.l] < belong[b.l];
}
int sum=0,num[N];
void update(int p,int d) {
    if(num[a[p]]==1&&d==-1) --sum;
    else if(num[a[p]]==0&&d==1) ++sum;
    num[a[p]]+=d;
}
bool cmp1(pp a,pp b) {
    return a.id < b.id;
}
int main() {
    while(scanf("%d%d",&n,&q)!=EOF) {
        for(int i=1;i<=n;++i)num[i]=0;
        build();
        for(int i=1;i<=n;++i)a[i]=read();
        for(int i=1;i<=q;++i) {
            Q[i].l=read(),Q[i].r=read();Q[i].id=i;
        }
        sort(Q+1,Q+1+q,cmp);
        int l=0, r=n+1;sum = 0;
        for(int i=1;i<=q;++i) {
            while(r<Q[i].r)update(r,-1),++r;
            while(r>Q[i].r)--r,update(r,1);
            while(l<Q[i].l)++l,update(l,1);
            while(l>Q[i].l)update(l,-1),--l;
            Q[i].ans = sum;
        }
        sort(Q+1,Q+1+q,cmp1);
        for(int i=1;i<=q;++i)printf("%d\n",Q[i].ans);
    }
    return 0;
}

posted @ 2018-07-19 23:07  RRRR_wys  阅读(446)  评论(0编辑  收藏  举报