17.8.27 校内赛 解题报告【卢卡斯定理】【dfs+hash】【线段树】

1.crf 出生的第一秒

解题报告
这道题显然是裸的卢卡斯定理,p还是质数。注意要开long long。代码如下:

#include<cmath>
#include<cstdio>
#include<algorithm>
#define NAME "first"
#define ll long long
using namespace std;
const int P=100000;
int n,m,mod;
ll jie[P+5];
ll qmul(ll a,ll b)//快速乘 
{
    int rt;
    for(rt=0;b;b>>=1,a=(a%mod+a%mod)%mod)
    if(b&1)rt=(rt%mod+a%mod)%mod;
    return rt;
}
ll qpow(ll a,ll b)//快速幂 
{
    int rt;
    for(rt=1;b;b>>=1,a=qmul(a,a))
    if(b&1)rt=qmul(rt,a);
    return rt;
}
ll C(ll n,ll m)
{
    if(m>n)return 0;
    if(n<mod)return qmul(qmul(jie[n],qpow(jie[m],mod-2)%mod),qpow(jie[n-m],mod-2)%mod);//没有到mod就套公式 
    return qmul(C(n/mod,m/mod),C(n%mod,m%mod));//过了mod就用卢卡斯定理 
}
int main()
{
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    scanf("%d%d%d",&n,&m,&mod);
    jie[0]=1;
    for(int i=1;i<=mod-1;i++)jie[i]=qmul((ll)i,jie[i-1]);//预处理阶乘 
    printf("%I64d",C((ll)n,(ll)m));
    return 0;
}

2.crf 出生的第二秒

解题报告
这道题是的一种做法是把一棵树拿来hash(dfs),获得一个hash值。询问的时候把询问的那棵树hash值算出来再去map里面查询就行了。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define NAME "second"
using namespace std;
const int N=100000 ;
unsigned long long base1[N+5]={1},base2[N+5]={1};
unsigned long long dpp1[N+5]={1},dpp2[N+5]={1},hash1,hash2;
map<unsigned long long,int>list_1,list_2;
struct edge
{
    int v,next;
}ed[N+5];
int n,m,q,head[N+5],siz[N+5],in[N+5],num; 
void build(int u,int v)
{
    in[v]++;
    ed[++num].v=v ;
    ed[num].next=head[u] ;
    head[u]=num ;
}
void dfs(int u,int dep)
{
    siz[u]=1;
    for(int i=head[u];i!=-1;i=ed[i].next)
    {
        dfs(ed[i].v,dep+1) ;
        siz[u]+=siz[ed[i].v] ;
    }
    hash1+=base1[siz[u]]*dpp1[dep] ;
    hash2+=base2[siz[u]]*dpp2[dep] ;
}
void clear()
{
    num=0;hash1=hash2=0;
    memset(in,0,(m+1)*sizeof(int));
    memset(head,-1,(m+1)*sizeof(int));
    memset(siz,0,(m+1)*sizeof(int));
}
int main()
{
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++)base1[i]=base1[i-1]*73U,base2[i]=base2[i-1]*47U,dpp1[i]=dpp1[i-1]*193U,dpp2[i]=dpp2[i-1]*233U;
    for(int i=1;i<=n;i++)
    {
        clear();
        for(int j=1;j<=m-1;j++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            build(u,v) ;
        }
        for(int j=1;j<=m;j++)if(!in[j]){dfs(j,1);break;}
        list_1[hash1]++;
        list_2[hash2]++;
    }
    for(int i=1;i<=q;i++)
    {   
        clear();
        for(int j=1;j<=m-1;j++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            build(u,v);
        }
        for(int j=1;j<=m;j++)if(!in[j]){dfs(j,1);break;}
        int t1=list_1[hash1],t2=list_2[hash2]; 
        printf("%d\n",min(t1,t2));
    }
    return 0;
}

3.crf 出生的第三秒

解题报告
这道题因为只有7种数字,用线段树维护每一段的7种数字分别有多少,合并就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
const int maxn=100010;
struct Node
{
    int cnt[7];
    int size;
    int cover;
    Node()
    {
        memset(cnt,0,sizeof(cnt));
        cover=-1;
    }
    inline void set(int cover)
    {
        this->cover=cover;
        for(int i=0;i<7;i++)
        if(i==cover)cnt[i]=size;
        else cnt[i]=0;
    }
    inline friend Node operator+(const Node &a,const Node &b)
    {
        Node c;
        for(int i=0;i<7;i++)c.cnt[i]=a.cnt[i]+b.cnt[i];
        return c;
    }
}t[maxn<<2];
int a[maxn];
inline void update(int rt)
{
    t[rt].size=t[rt<<1].size+t[rt<<1|1].size;
    for(int i=0;i<7;i++)t[rt].cnt[i]=t[rt<<1].cnt[i]+t[rt<<1|1].cnt[i];
}
inline void pushdown(int rt)
{
    if(t[rt].cover!=-1)
    {
        t[rt<<1].set(t[rt].cover);
        t[rt<<1|1].set(t[rt].cover);
        t[rt].cover=-1;
    }
}
inline void build(int l,int r,int rt)
{
    if(l==r)
    {
        t[rt].size=1;
        t[rt].cnt[a[l]]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    update(rt);
}
inline Node query(int l,int r,int rt,int L,int R)
{
    if(l>=L&&r<=R)return t[rt];
    pushdown(rt);
    int mid=(l+r)>>1;
    Node answer;
    if(L<=mid)answer=answer+query(l,mid,rt<<1,L,R);
    if(R>mid)answer=answer+query(mid+1,r,rt<<1|1,L,R);
    return answer;
}
inline void change(int l,int r,int rt,int L,int R,int cover)
{
    if(l>=L&&r<=R)
    {
        t[rt].set(cover);
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid)change(l,mid,rt<<1,L,R,cover);
    if(R>mid)change(mid+1,r,rt<<1|1,L,R,cover);
    update(rt);
}
int main()
{
    freopen("third.in","r",stdin);
    freopen("third.out","w",stdout);
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]--;
    }
    build(1,n,1);
    for(int i=1;i<=q;i++)
    {
        int l,r,opt;
        scanf("%d%d%d",&l,&r,&opt);
        Node answer=query(1,n,1,l,r);
        int nowl=l;
        if(opt==0)
        {
            for(int j=0;j<7;j++)
            if(answer.cnt[j])
            {
                change(1,n,1,nowl,nowl+answer.cnt[j]-1,j);
                nowl+=answer.cnt[j];
            }
        }
        else
        {
            for(int j=6;j>=0;j--)
            if(answer.cnt[j])
            {
                change(1,n,1,nowl,nowl+answer.cnt[j]-1,j);
                nowl+=answer.cnt[j];
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        Node answer=query(1,n,1,i,i);
        int x=-1;
        for(int j=0;j<7;j++)if(answer.cnt[j])x=j+1;
        printf("%d%c",x,i==n?'\n':' ');
    }
    return 0;
}

以上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值