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. C语言开发中常用英文缩写

    BIOS(Basic Input Output System): 基本输入输出系统 reference: https://baike.baidu.com/item/bios/91424?fr=alad ...

  2. 全面学习 Python 包:包的构建与分发

    首发于公众号:Python编程时光 1. 为什么需要对项目分发打包? 平常我们习惯了使用 pip 来安装一些第三方模块,这个安装过程之所以简单,是因为模块开发者为我们默默地为我们做了所有繁杂的工作,而 ...

  3. 谷歌浏览器解决ajax跨域问题

    在用mui和H5+做混合开发,会利用HBuildx去真机调试,可真机调试总有问题所在,懂得人自然懂,而我们直接打开页面显示的只有一个静态的页面,是获取不到数据的在这里我想说的不是代码中利用jsonp, ...

  4. UI5-技术篇-JS函数eval动态执行

    <html lang="en"> <head> <meta charset="utf-8" /> <title> ...

  5. [C#]DataTable转string[]

    来源:https://zhidao.baidu.com/question/1754089856824824548.html string[] ary = Array.ConvertAll<Dat ...

  6. css设置图片百分比显示,最简洁的代码

    css代码: .img-box { padding-bottom: 100%; } .img-box img { position: absolute; top:; bottom:; left:; r ...

  7. mysql 模糊查询like小结

    以不完整的条件进行查询 因为条件是模糊的 所以叫模糊查询,可以对有相同信息的数据快速归类 . like  运算符:可以很好的通过%和-两种通配符对数据进行筛选查询 %(所有)放在条件前中后.可查询包含 ...

  8. 主流WEB服务器大对比(Apache,Nginx,Lighttpd)

    一.软件介绍(apache  lighttpd  nginx) 1. lighttpd  Lighttpd 是一个具有非常低的内存开销, cpu 占用率低,效能好,以及丰富的模块等特点. lightt ...

  9. @JsonIgnore注解

    注解名称:@JsonIgnore 作用:在实体类向前台返回数据时用来忽略不想传递给前台的属性或接口. Eg:User实体中会有字段password字段,当返回用户信息给前台的时候,当然是不希望将pas ...

  10. unity 之协程返回值

    yield return null; // 下一帧再执行后续代码yield return 6;//(任意数字) 下一帧再执行后续代码yield break; //直接结束该协程的后续操作yield r ...