您的位置:首页 > 其它

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

2017-08-27 17:17 411 查看
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
,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;
}


以上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: