您的位置:首页 > 其它

【学姐的胡策】训练8.17(Lucas+线段树并查集)

2017-08-17 20:47 381 查看
题目:



题解:

50pts:预处理组合数+Lucas

100pts:数位dp+Lucas【挖坑待填】

代码:

50pts呜哇我考试是不带脑子吧,Lucas的时候m都没有带longlong啊

#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
LL n,k;
const int Mod=2333;
int f[Mod+10][Mod+10];
int Lucas(LL m,int n)
{
int ans=1;
for (;n;n/=Mod,m/=Mod)
ans=ans*f[m%Mod][n%Mod]%Mod;
return ans%Mod;
}
int main()
{
freopen("house.in","r",stdin);
freopen("house.out","w",stdout);
int i,j,T;
for (i=0;i<2333;i++) f[i][0]=1;
for (i=1;i<2333;i++)
for (j=1;j<2333;j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1])%Mod;
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld",&n,&k);
int ans=1;
for (i=1;i<=k;i++)
ans=(Lucas(n,i)+ans)%Mod;
printf("%d\n",ans);
}
}


题目:

学姐的原题





题解:

良心学姐还有20pts纯暴力。

【记得以前天宇哥哥讲过这道题?】

静态序列查询——线段树!

注意到n非常的小,那么我们可以把每一列看成一个整体,在线段树里维护并查集

每个节点维护这个区间的合并情况,只需要记录最左边和最右边的两列就可以了

再记录一下区间内的连通块个数

Update的时候用一个临时数组来完成

枚举交界处看是否需要合并

感觉代码很清晰漂亮呢,觉得数组的大小还是应该好好把握,比如fa,线段树tree等

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define M 100050
using namespace std;
struct seg
{
int l[12],r[12],s;
seg(){memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); s=0;}
}tree[M*4];
int fa[M*10],n,num[M][12],jz[M][12],m;
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int merge(int x,int y)
{
int xx=find(x),yy=find(y);
if (xx!=yy) {fa[xx]=yy; return 1;}
return 0;
}
void init(seg &now,int p)
{
int i;
for (i=1;i<=n;i++) fa[num[p][i]]=num[p][i];
now.s=n;
for (i=1;i<n;i++)
if (jz[p][i]==jz[p][i+1])
now.s-=merge(num[p][i],num[p][i+1]);
for (i=1;i<=n;i++) now.l[i]=now.r[i]=find(num[p][i]);
}
seg updata(seg lc,seg rc,int l,int ll,int r,int rr)
{
int i;seg now;
now.s=lc.s+rc.s;
for (i=1;i<=n;i++)
{
fa[lc.l[i]]=lc.l[i];
fa[lc.r[i]]=lc.r[i];
fa[rc.l[i]]=rc.l[i];
fa[rc.r[i]]=rc.r[i];
}
for (i=1;i<=n;i++)
if (jz[ll][i]==jz[r][i]) now.s-=merge(lc.r[i],rc.l[i]);
for (i=1;i<=n;i++)
now.l[i]=find(lc.l[i]),now.r[i]=find(rc.r[i]);
return now;
}
void build(int now,int l,int r)
{
if (l==r){init(tree[now],l); return;};
int mid=(l+r)>>1;
if (l<=mid) build(now<<1,l,mid);
if (r>mid) build(now<<1|1,mid+1,r);
tree[now]=updata(tree[now<<1],tree[now<<1|1],l,mid,mid+1,r);
}
seg ask(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) return tree[now];
int mid=(l+r)>>1;
seg lc,rc; lc.s=rc.s=-1;
if (lrange<=mid) lc=ask(now<<1,l,mid,lrange,rrange);
if (rrange>mid) rc=ask(now<<1|1,mid+1,r,lrange,rrange);
if (lc.s==-1) return rc;
if (rc.s==-1) return lc;
return updata(lc,rc,max(l,lrange),mid,mid+1,min(r,rrange));
}
int main()
{
int q,i,j,l,r;
scanf("%d%d%d",&n,&m,&q);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
scanf("%d",&jz[j][i]);
int cnt=0;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
num[i][j]=++cnt;
build(1,1,m);
while (q--)
{
scanf("%d%d",&l,&r);
printf("%d\n",ask(1,1,m,l,r).s);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: