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. 5_PHP数组_3_数组处理函数及其应用_2_数组统计函数

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. 一.数组统计函数 数组统计函数是指统计数组各元素的值,并对这些值进行简单分析. 1. count() 函数 该函数 ...

  2. 【转载】Java对象的生命周期

    Java对象的生命周期 在Java中,对象的生命周期包括以下几个阶段: 1.      创建阶段(Created) 2.      应用阶段(In Use) 3.      不可见阶段(Invisib ...

  3. 简述几个css hack?【CSS】

    (1) 图片间隙  在div中插入图片,图片会将div下方撑大3px. hack1:将<div>与<img>写在同一行. hack2:给<img>添加display ...

  4. CentOS 7 - 安装PostgreSQL

    一,用yum安装PostgreSQL . 选择安装版本和服务器平台后,执行安装命令,例如我要安装是9.6版本,平台是CentOS 7. https://www.postgresql.org/downl ...

  5. android AlertDialog控件使用

    1.先创建activity_alert_dialog.xml <?xml version="1.0" encoding="utf-8"?> < ...

  6. mac环境下Android 反编译

    连接地址: https://www.jianshu.com/p/3a305f32c4a3

  7. 服务网关ZuulFilter过滤器--pre/post/error的用法(校验请求信息,获取路由后的请求/响应信息,处理服务网关异常)

    微服务中Zuul服务网关一共定义了四种类型的过滤器: pre:在请求被路由(转发)之前调用 route:在路由(请求)转发时被调用 error:服务网关发生异常时被调用 post:在路由(转发)请求后 ...

  8. 利用.bat脚本使得可运行jar开机自动运行

    1.利用Elipse到处可运行的jar包 2.写.bat脚本[点此下载],相应目录自己根据需要修改即可 3.将此脚本放在"启动"文件夹中

  9. 【转】Anaconda安装与使用

    PS:这还是17年一次数据挖掘训练营使用的软件 [转至]https://blog.csdn.net/m0_37605642/article/details/98726766 安装和配置 1.在官网或清 ...

  10. layui 单选框、复选框、下拉菜单 不显示问题 记录

    1. 如果是 ajax嵌套了 页面, 请确保  只有最外层的页面引入了 layui.css 和 layui.js 内层页面 切记不要再次引入 2. layui.use(['form', 'upload ...