Description

 Solution

T1 shopping

目测是插板法乱搞一下

发现题解写的是容斥dp:

\[ans = \sum_i (-1)^ig[i]
\]

\(g[i]\)表示的有\(i\)个商店必然达到上限的方案数

考虑转化,设\(f[i][j]\)表示前\(i\)个商店,必然超过限制的商店的(上限+1)的和是\(j\)

\[f[i][j]=f[i-1][j]-f[i-1][j-w[i]-1]
\]

所以答案就可以这样计算:

\[ans=\sum_i f[n][i] C(k+n-1,n-1)
\]

后面那一块就是插板法

/*容斥dp */
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MN=5e6+5,MM=301,mod=1e9+7;
int n,m,k,wi[MM],f[2][MM*MM+MN],fac[MN<<1],inv[MN<<1];
int C(int x,int y){if(y<=0)return 1;return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;}
int fpow(int x,int M){int r=1;for(;M;M>>=1,x=1ll*x*x%mod)if(M&1)r=1ll*r*x%mod;return r;}
int main()
{
register int i,j,qz=0,ans=0;
n=read(),m=read(),k=read();
for(i=1;i<=m;++i) wi[i]=read(),qz+=wi[i];
for(fac[0]=i=1;i<=n+k;++i)fac[i]=1ll*fac[i-1]*i%mod;
for(inv[n+k]=fpow(fac[n+k],mod-2),i=n+k-1;~i;--i)inv[i]=1ll*inv[i+1]*(i+1)%mod;
f[1][wi[1]+1]=mod-1;f[1][0]=1;
for(i=2;i<=m;++i)
{
for(j=0;j<=qz+m;++j)
{
int l=j-wi[i]-1;f[i&1][j]=f[(i&1)^1][j];
if(l>=0) f[i&1][j]+=mod-f[(i&1)^1][l],f[i&1][j]%=mod;
}
}
for(i=0;i<=k;++i)ans+=1ll*f[m&1][i]*C(k+n-i-1,n-1)%mod,ans%=mod;
printf("%d\n",ans);
}

T2 highway

发现\(n\)很小,所以对于已经按照边权排号序的边集,求\(Kruskal\)生成森林的只要\(O(\alpha(n)n)\)

考虑线段树维护区间,每个节点保存用到的边(有序的),合并的时候做一次\(Kruskal\)即可

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define reg register
const int MN=105,MM=1e5+5;
int n,m,q;
struct edge{int u,v,w;}e[MM];
struct Node
{
vector<int> ed;
int val;
Node(){ed.clear();val=0;}
}T[MM<<2];
int fa[MN];
int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);}
bool union_(int x,int y){x=getf(x);y=getf(y);if(x==y)return false;fa[x]=y;return true;}
Node merge(Node x,Node y)
{
reg int si=x.ed.size(),sj=y.ed.size(),i,j;
for(i=1;i<=n;++i) fa[i]=i;
#define J y.ed[j]
#define I x.ed[i]
Node r;
for(i=0,j=0;i<si||j<sj;)
{
if(i==si||(j!=sj&&e[J].w<e[I].w))
{
if(union_(e[J].u,e[J].v)) r.ed.push_back(J),r.val+=e[J].w;
++j;continue;
}
if(union_(e[I].u,e[I].v)) r.ed.push_back(I),r.val+=e[I].w;
++i;
}
return r;
}
void build(int x,int l,int r)
{
if(l==r){T[x].ed.push_back(l);T[x].val=e[l].w;return;}
int mid=(l+r)>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
T[x]=merge(T[x<<1],T[x<<1|1]);
}
Node query(int x,int l,int r,int a,int b)
{
if(l==a&&r==b) return T[x];
int mid=(l+r)>>1;
if(b<=mid) return query(x<<1,l,mid,a,b);
if(a>mid) return query(x<<1|1,mid+1,r,a,b);
else return merge(query(x<<1,l,mid,a,mid),query(x<<1|1,mid+1,r,mid+1,b));
}
int main()
{
n=read();m=read();q=read();
reg int i,l,r;
for(i=1;i<=m;++i) e[i].u=read(),e[i].v=read(),e[i].w=read();
build(1,1,m);
while(q--)
{
l=read(),r=read();
printf("%d\n",query(1,1,m,l,r).val);
}
return 0;
}

T3 sailing

第一步,我们考虑舰队可以”整体地“位于哪几个位置

把环境和舰队的图都转化成一个\(01\)序列,可以位于一个位置当且仅当在某个区间中没有两个数同为\(1\)

考虑把其中一个序列倒序处理,就可以用\(NTT\)算出上面的答案

第二步,可以位于某个位置并不代表一定可以移动的到

从一个一定满足的位置(比如说舰队的原位置)开始\(bfs\),显然所有合法的位置都是相互联通的

第三步,求可以到达的格子数

一个格子可以到达,说明将舰队的\(01\)序列放在某个合法的位置上,这个位置是\(1\)

显然也可以用\(NTT\)来解决

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define reg register
const int MN=705,P=998244353,g=3,invg=332748118;
int n,m;
int a[MN*MN*4],b[MN*MN*4],c[MN*MN*4],N,di,invN,pos[MN*MN*4];
char mp[MN][MN];
bool rea[MN][MN];
int fpow(int x,int m){int r=1;for(;m;m>>=1,x=1ll*x*x%P)if(m&1)r=1ll*r*x%P;return r;}
void NTT(int *a,int type)
{
reg int wi,w,i,j,p,k;
for(i=0;i<N;++i)if(i<pos[i])std::swap(a[i],a[pos[i]]);
for(i=1;i<N;i<<=1)
{
wi=fpow(type>0?g:invg,(P-1)/(i<<1));
for(j=i<<1,p=0;p<N;p+=j)
for(w=1,k=0;k<i;++k,w=1ll*w*wi%P)
{
int X=a[p+k],Y=1ll*a[i+p+k]*w%P;
a[p+k]=(X+Y)%P;a[i+p+k]=(X-Y+P)%P;
}
}
if(type<0)for(i=0;i<N;++i)a[i]=1ll*a[i]*invN%P;
}
std::queue<std::pair<int,int> > q;
const int dx[4]={0,-1,0,1},dy[4]={1,0,-1,0};
void bfs(int x,int y)
{
q.push(make_pair(x,y));rea[x][y]=false;
while(!q.empty())
{
int X=q.front().first,Y=q.front().second;q.pop();
a[(X-1)*m+Y]=1;
for(reg int i=0;i<4;++i)if(rea[X+dx[i]][Y+dy[i]])
rea[X+dx[i]][Y+dy[i]]=false,q.push(make_pair(X+dx[i],Y+dy[i]));
}
}
int main()
{
int i,j,x1=P,x2=-P,y1=P,y2=-P,ans=0;
n=read();m=read();
for(i=1;i<=n;++i) scanf("%s",mp[i]+1);
for(i=1;i<=n;++i)for(j=1;j<=m;++j)
{
if(mp[i][j]=='#') a[(i-1)*m+j]=1;
if(mp[i][j]=='o') x1=min(x1,i),x2=max(x2,i),y1=min(y1,j),y2=max(y2,j);
}
int T=(x2-x1)*m+y2-y1+1;
for(i=1;i<=n;++i)for(j=1;j<=m;++j)
if(mp[i][j]=='o') b[(i-x1)*m+j-y1+1]=c[T-(i-x1)*m-j+y1]=1;
for(N=1,di=0;N<=m*n*2;N<<=1,++di);invN=fpow(N,P-2);
for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
NTT(a,1);NTT(b,1);NTT(c,1);
for(i=0;i<N;++i) a[i]=1ll*a[i]*c[i]%P;
NTT(a,-1);
for(i=1;i+(x2-x1)<=n;++i)for(j=1;j+(y2-y1)<=m;++j)if(a[T+(i-1)*m+j]==0)rea[i][j]=true;
memset(a,0,sizeof a);bfs(x1,y1);NTT(a,1);
for(i=0;i<N;++i) a[i]=1ll*a[i]*b[i]%P;
NTT(a,-1);
for(i=2;i<=n*m+1;++i) if(a[i]) ++ans;
return 0*printf("%d\n",ans);
}

Blog来自PaperCloud,未经允许,请勿转载,TKS!

FCS省选模拟赛 Day1的更多相关文章

  1. FCS省选模拟赛 Day7

    Description  Solution T1 island 考虑把问题成两部分计算 纵坐标的距离和很好计算,在输入的同时一次计算了就完事 横坐标又分成两部分 分别在\(y\)轴不同侧的矩形的距离和 ...

  2. FCS省选模拟赛 Day3

    Description  Solution T1 game 咕咕咕 T2 string fail树各个节点的深度之和怎么求? 我们考虑每个前缀的深度是什么 发现这个值就相当于有多少个前缀等于它的后缀 ...

  3. FCS省选模拟赛 Day4

    传送门 Solution Code  /* 斯坦纳树:O(n*3^n+kE*2^n) 暂且把O(k*E)当成是spfa的复杂度 15:15~16:20 原题:bzoj_4774 */ #include ...

  4. FCS省选模拟赛 Day5

    传送门 Solution Code  #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?( ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #48 - Streaming #3 (NOIP模拟赛Day1)

    A.数三角形 题目:http://www.contesthunter.org/contest/CH%20Round%20%2348%20-%20Streaming%20%233%20(NOIP模拟赛D ...

  9. CH Round #54 - Streaming #5 (NOIP模拟赛Day1)

    A.珠 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2354%20-%20Streaming%20%235%20(NOIP模拟赛Day1)/珠 题解:sb题, ...

随机推荐

  1. 转 如何在调用WCF服务之前弹出一个确认对话框

    自定义InteractiveChannelInitializer(InvocationConfirmationInteractiveChannelInitializer)定义如下.我们在BeginDi ...

  2. python 包 安装 加速 pip anaconda

    使用 -i 参数指定源,豆瓣的很快: pip install web.py -i http://pypi.douban.com/simple anaconda: ~/.condarc channels ...

  3. usercript and passwdcript array

    usercript and passwdcript array ######################## # nsnet_usercript # xxd -g 4 -c 16 -s +$(( ...

  4. 2019年北航OO第4单元(UML)总结

    1 架构设计 经过了接近一学期的程序设计训练,在这一单元的第一次作业中我就非常注重架构的设计,竭力避免像之前一样陷入"第一次作业凑合,第二次作业重构"的不健康的迭代模式.整体上来说 ...

  5. dubbo源码阅读之负载均衡

    负载均衡 在之前集群的文章中,我们分析了通过监听注册中心可以获取到多个服务提供者,并创建多个Invoker,然后通过集群类如FailoverClusterInvoker将多个Invoker封装在一起, ...

  6. element-ui DatePicker 日期格式处理

    1.使用DatePicker 日期选择器得到的日期格式是这样的 解决方案,添加 value-format="yyyy-MM-dd" <el-date-picker type= ...

  7. JavaScript中匿名函数this指向问题

    this对象是在运行时基于函数执行环境绑定的,在全局函数中,this=window,在函数被作为某个对象的方法调用时,this等于这个对象. 但是匿名函数的执行环境是全局性的,所以匿名函数的this指 ...

  8. HP-UX 解压缩tar.gz

    对于tar.gz包分两步: gunzip *.tar.gz 解压为tar包 tar xf *.tar 解压完成

  9. Androidx初尝及其新旧包对照表

    x的最低实验条件 AndroidStudio 3.2.0+ gradle:gradle-4.6以上 本次实验条件: AndroidStudio 3.3 (强制要求最低gradle版本为gradle-4 ...

  10. I、Mac 下的Vue

    Mac 下的Vue 1. 安装brew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/i ...