[NOIP模拟23]题解
中间鸽了好几篇啊QAQ……有时间再补吧……
A.mine
sbdp,考场上写的巨麻烦不过还是能A的(虽然MLE了……每一维都少开1就A掉了555)。设$dp[i][j][k]$为枚举到第i位,第i位是j,第i-1位是k的方案数。j和k都是0~3的整数,分别代表有前后几个雷/就是雷。
然后大力分类讨论即可
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+;
typedef long long ll;
const ll mod=1e9+;
char s[N];
int str[N];
ll dp[N][][];//到第i位 第i位是j 第i-1位是k
//0 0
//1 1
//2 2
//3 *
int len;
void mmod(ll &x)
{
while(x>=mod)x=x-mod;
}
bool isbomb(int x)
{
if(str[x]==||str[x]==)return ;
return ;
}
bool judge()
{
for(int i=;i<=len;i++)
{
if(str[i]==)continue;
if(str[i]==&&(str[i-]==||(str[i-]==&&str[i+]==)||(!isbomb(i-)&&!isbomb(i+))))return ;
if(str[i]==&&(!isbomb(i-)||!isbomb(i+)))return ;
}
return ;
}
int main()
{
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=len;i++)
if(s[i]=='')s[i-]=s[i+]='*';
if(len==)
{
if(s[]=='*'||s[]=='')puts("");
else puts("");
return ;
}
for(int i=;i<=len;i++)
{
if(s[i]=='')str[i]=;
else if(s[i]=='')str[i]=;
else if(s[i]=='')str[i]=;
else if(s[i]=='*')str[i]=;
else if(s[i]=='?')str[i]=;
}
if(!judge())
{
puts("");
return ;
}
if(str[]!=)
{
if(str[]==)dp[][][]=;
else if(str[]==)dp[][][]=;
else if(str[]==)dp[][][]=;
}
else dp[][][]=dp[][][]=dp[][][]=;
for(int i=;i<=len;i++)
{
// cout<<str[i]<<endl;
if(str[i]==||str[i]==)
{
mmod(dp[i][][]+=dp[i-][][]);
mmod(dp[i][][]+=(dp[i-][][]+dp[i-][][]));
}
if(str[i]==||str[i]==)
{
mmod(dp[i][][]+=dp[i-][][]+dp[i-][][]+dp[i-][][]);
mmod(dp[i][][]+=dp[i-][][]+dp[i-][][]);
mmod(dp[i][][]+=dp[i-][][]);
}
if(str[i]==||str[i]==)
{
mmod(dp[i][][]+=dp[i-][][]+dp[i-][][]+dp[i-][][]);
}
if(str[i]==||str[i]==)
{
mmod(dp[i][][]+=dp[i-][][]+dp[i-][][]);
mmod(dp[i][][]+=dp[i-][][]);
mmod(dp[i][][]+=dp[i-][][]+dp[i-][][]+dp[i-][][]);
}
}
ll ans=;
if(str[len]!=&&str[len-]!=)ans=dp[len][str[len]][str[len-]];
else if(str[len]==&&str[len-]!=)
{
for(int i=;i<=;i++)
{
int j=str[len-];
if(i==&&(j==||j==))continue;
if(i==&&(j!=))continue;
if(i==)continue;
if(i==&&j==)continue;
mmod(ans+=dp[len][i][str[len-]]);
}
}
else if(str[len]!=&&str[len-]==)
{
for(int j=;j<=;j++)
{
int i=str[len];
if(i==&&(j==||j==))continue;
if(i==&&(j!=))continue;
if(i==)continue;
if(i==&&j==)continue;
mmod(ans+=dp[len][str[len]][j]);
}
}
else
{
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
if(i==&&(j==||j==))continue;
if(i==&&(j!=))continue;
if(i==)continue;
if(i==&&j==)continue;
mmod(ans+=dp[len][i][j]);
}
}
cout<<ans<<endl;
return ;
}
一开始那个$judge()$是判不合法情况。A掉之后突然发现我的程序好像遇到一开始就不合法的情况还是会有方案,所以特判了一下。
B.water
一个块的最终高度(初始高度+积水高度)就是从这个块走出矩形的路径上最大值的最小值,即把路径定义为权值取max而非权值和后的最短路。那么就直接相邻块建图,边界块都连到一个源点上,之后从源点跑dj即可。有点像网络流。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#define pa pair<int,int>
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int N=,M=;
const int dx[]={,,,-},
dy[]={,,-,};
int n,m;
int a[N][N];
int to[M],nxt[M],head[M],len[M],tot;
void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
len[tot]=z;
head[x]=tot;
}
int id(int i,int j){return (i-)*m+j;}
int dis[M],vis[M];
void dj(int s)
{
memset(dis,0x3f,sizeof(dis));
priority_queue<pa> q;
dis[s]=;q.push(make_pair(,s));
while(!q.empty())
{
int x=q.top().second;q.pop();
if(vis[x])continue;
vis[x]=;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(dis[y]>max(dis[x],len[i]))
{
dis[y]=max(dis[x],len[i]);
q.push(make_pair(-dis[y],y));
}
}
}
} int main()
{
n=read();m=read();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
a[i][j]=read();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
for(int k=;k<;k++)
{
int nx=i+dx[k],ny=j+dy[k];
if(nx<||nx>n||ny<||ny>m)add(n*m+,id(i,j),max(a[i][j],)),add(id(i,j),n*m+,max(a[i][j],));
else add(id(i,j),id(nx,ny),max(a[i][j],a[nx][ny]));
}
}
dj(n*m+);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
printf("%d ",dis[id(i,j)]-a[i][j]);
putchar('\n');
}
return ;
}
C.gcd
披着数据结构题的毒瘤数论。
需要维护三个量:
$f[]$:选中集合中gcd为i的数对个数
$g[]$:选中集合中gcd为i的倍数的数对个数
$s[]$:选中集合中i的倍数的个数
首先$s[]$的值是很好得到的,每次加入数时枚举它的因子$i$,$s[i]++$即可。
那$s[]$的意义何在呢?它可以帮助我们快速得到$g[]$。显然$g[i]=C_{s[i]}^2$。
又因为$g[i]=\sum \limits_{i|d} f[d]$,可以用第二类莫比乌斯反演得到:
$f[i]=\sum \limits_{i|d} \mu (\frac{d}{i}) g[d]$
$f[1]$即为所求,所以每次更改选中状态时枚举更改的数的因子,更新它的$s[]$,进而更新它的$g[]$。
ans可以通过减去原来的g再加上新g得到。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=,M=;
int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch))x=x*+ch-'',ch=getchar();
return x*f;
}
typedef long long ll;
bool vis[M];
int pr[M],tot,mu[M];
void ini()
{
mu[]=;
for(int i=;i<=M-;i++)
{
if(!vis[i])pr[++tot]=i,mu[i]=-;
for(int j=;j<=tot&&i*pr[j]<=M-;j++)
{
vis[i*pr[j]]=;
if(i%pr[j])mu[i*pr[j]]=-mu[i];
else
{
mu[i*pr[j]]=;
break;
}
}
}
}
int n,m;
int s[M],ctrl[N],a[N];
int main()
{
n=read();m=read();
ini();
for(int i=;i<=n;i++)
a[i]=read();
ll ans=;
while(m--)
{
int x=read();
for(int i=;i*i<=a[x];i++)
{
if(a[x]%i==)
{
if(!ctrl[x])ans+=1LL*mu[i]*s[i];
else ans-=1LL*(s[i]-)*mu[i];
if(ctrl[x])s[i]--;
else s[i]++;
if(i*i==a[x])continue;
if(!ctrl[x])ans+=1LL*mu[a[x]/i]*s[a[x]/i];
else ans-=1LL*(s[a[x]/i]-)*mu[a[x]/i];
if(ctrl[x])s[a[x]/i]--;
else s[a[x]/i]++;
}
}
ctrl[x]^=;
printf("%lld\n",ans);
}
return ;
}
[NOIP模拟23]题解的更多相关文章
- noip模拟23[联·赛·题]
\(noip模拟23\;solutions\) 怎么说呢??这个考试考得是非常的惨烈,一共拿了70分,为啥呢 因为我第一题和第三题爆零了,然后第二题拿到了70分,还是贪心的分数 第一题和第二题我调了好 ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- HZOJ 20190818 NOIP模拟24题解
T1 字符串: 裸的卡特兰数题,考拉学长讲过的原题,就是bzoj3907网格那题,而且这题更简单,连高精都不用 结论$C_{n+m}^{n}-C_{n+m}^{n+1}$ 考场上10min切掉 #in ...
- 「题解」NOIP模拟测试题解乱写I(29-31)
NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...
- HGOI NOIP模拟4 题解
NOIP国庆模拟赛Day5 题解 T1 马里奥 题目描述 马里奥将要参加 NOIP 了,他现在在一片大陆上,这个大陆上有着许多浮空岛,并且其中一座浮空岛上有一个传送门,马里奥想要到达传送门从而前往 N ...
- [NOIP模拟13]题解
A.矩阵游戏 其实挺水的? 考场上根本没有管出题人的疯狂暗示(诶这出题人有毛病吧这么简单的东西写一大堆柿子),而且推公式能力近乎没有,所以死掉了. 很显然乘法有交换率结合率所以操作顺序对最终结果没什么 ...
- 8.3 NOIP 模拟12题解
话说这次考试T1和T2是真的水,然而T1CE,T2TLE,T3CE 这不就是在侮辱我的智商啊!之前本机编译都是c++,以后要用c++11. 这次的T1就是一个大型找规律,我的规律都找出来了,但是竟然用 ...
随机推荐
- UNP学习 多播
一.概述 单播地址标识单个接口,广播地址标识子网上的所有接口,多播地址标识一组接口. 单播和广播是编址方案的两个极端,多播的目的就在于提供一种折衷的方案. 二.多播地址 我们必须区分IPv4多播地址和 ...
- React的contextType的使用方法简介
上一篇介绍了Context的使用方法.但是Context会让组件变得不纯粹,因为依赖了全局变量.所以这决定了Context一般不会大规模的使用.所以一般在一个组件中使用一个Context就好. 由于C ...
- Linux系统之-TCP-IP链路层
一.基本 网络层协议的数据单元是 IP 数据报 ,而数据链路层的工作就是把网络层交下来的 IP 数据报 封装为 帧(frame)发送到链路上,以及把接收到的帧中的数据取出并上交给网络层. 为达到这一目 ...
- HTML中多媒体标签技术说明
在纯文本的HTML页面中加入图片,给原来单调乏味的页面添加生气.HTML语言中利用<IMG>标记插入图片. 1.图片标记<IMG>及其属性 在网站上,网页设计者都使用了大量精心 ...
- PHP面试 MySQL的高可扩展和高可用
MySQL的高可扩展和高可用 面试题一 MySQL分表和分区的工作原理,分表和分区的使用场景和优缺点. 分区表的原理 对用户而言,分区表时一个独立的逻辑表,但是底层MySQL将其分成了多个物理子表,这 ...
- java 并发——ReentrantLock
java 并发--ReentrantLock 简介 public class ReentrantLock implements Lock, java.io.Serializable { // 继承了 ...
- span 设置inline-block 写文字的span错位
写一个如下图这样排版 设置几个span为inline-block 中间的span写了文字的span错位了 解决方案 给span添加 vertical-align: top
- 37-python基础-python3-字典的常用方法-keys()-values()-items()
有 3 个字典方法,它们将返回类似列表的值,分别对应于字典的键.值和键-值对:keys().values()和 items(). 这些方法返回的值不是真正的列表,它们不能被修改,没有append()方 ...
- join(long)方法和sleep(long)方法的比较
join(long)方法的源代码 public final synchronized void join(long millis) throws InterruptedException { long ...
- Java Socket NIO示例总结
Java NIO是非阻塞IO的实现,基于事件驱动,非常适用于服务器需要维持大量连接,但是数据交换量不大的情况,例如一些即时通信的服务等等,它主要有三个部分组成: Channels Buffers Se ...