【学姐的胡策】训练8.17(Lucas+线段树并查集)
2017-08-17 20:47
381 查看
题目:
题解:
50pts:预处理组合数+Lucas
100pts:数位dp+Lucas【挖坑待填】
代码:
50pts呜哇我考试是不带脑子吧,Lucas的时候m都没有带longlong啊
题目:
学姐的原题
题解:
良心学姐还有20pts纯暴力。
【记得以前天宇哥哥讲过这道题?】
静态序列查询——线段树!
注意到n非常的小,那么我们可以把每一列看成一个整体,在线段树里维护并查集
每个节点维护这个区间的合并情况,只需要记录最左边和最右边的两列就可以了
再记录一下区间内的连通块个数
Update的时候用一个临时数组来完成
枚举交界处看是否需要合并
感觉代码很清晰漂亮呢,觉得数组的大小还是应该好好把握,比如fa,线段树tree等
代码:
题解:
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); } }
相关文章推荐
- 【学姐的胡策】训练8.18(KMP+dp)
- POJ训练计划1611_The Suspects(并查集)
- 【HDU 1394】Minimum Inversion Number 【线段树 训练2】
- hpu暑假训练D - How Many Tables 【并查集】
- 【糟糕的胡策】训练2.25(乱搞+hash+点分治)
- 【充满原题的胡策】训练2.26 T1(线性基+讲解)
- CSU-ACM2017暑期训练10-并查集&&HASH C - 食物链 POJ - 1182 (并查集好题)
- POJ训练计划2528_Mayor's posters(线段树/成段更新+离散化)
- hdu 4619 warm up 2 并查集或搜索都可以做出来的题 2013多校联合训练第二场
- 数据结构(线段树)训练
- HDU 3974 Assign the task (并查集 || 线段树)
- 2017多校训练第二周-Connected Components-并查集
- POJ训练计划2828_Buy Tickets(线段树/单点更新)
- [dfs序][线段树][并查集] JZOJ P3766 大融合
- 纪中训练 day13 线段树
- BZOJ.3673/3674.可持久化并查集(可持久化线段树 按秩合并/启发式合并)
- 【CDOJ 1328】卿学姐与诡异村庄 【并查集】
- 【充满原题的胡策】训练2.26 T2(三维计算几何)
- 【并查集套可持久化线段树】【bzoj 2733】: [HNOI2012]永无乡
- HDU 5861 Road (线段树或并查集)