NOIP模拟测试19
T1:
题目大意:将一颗有N个节点的树分割,使得每个联通块大小相等,问一共有多少方案。(N<=1000000)
首先,一条很显然的性质,每个联通块的大小一定是N的因子。
然后,我们可以对于每个因子d,DFS一遍,维护一个si值,代表该子树中有多少节点是连通的,一旦这个值等于d,将这颗子树切掉,若这个值大于d,则判定不合法。
这个方法每次DFS只验证一个因子,效率较低。
我们可以只进行一遍DFS将每颗子树的大小存进一个桶里。一颗子树被切掉,当且仅当该子树中剩下的点共有d个,若d合法,则当前子树原有的节点数应为d的倍数,我们可以枚举每个因子的每个倍数,在桶里查询,若总数为N/d,则合法。
时间复杂度为$\sum_{d|N}d=O(Nlog_2N)$
Code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=;
int n,nm=,m=,ans=;
int fi[N],d[],s[N];
struct edge{
int v,ne;
}e[N<<];
void add(int x,int y)
{
e[++nm].v=y;
e[nm].ne=fi[x];fi[x]=nm;
}
int read()
{
int s=;char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<=''){
s=(s<<)+(s<<)+c-'';
c=getchar();
}
return s;
}
void divide()
{
for(int i=;i<=sqrt(n);i++){
if(n%i==){
d[++m]=i;
if(i*i!=n) d[++m]=n/i;
}
}
}
bool dfs(int x,int p)
{
s[x]=;
for(int i=fi[x];i!=;i=e[i].ne){
int y=e[i].v;
if(y==p) continue;
dfs(y,x);
s[x]+=s[y];
}
}
bool check(int x)
{
int tot=;
for(int i=x;i<=n;i+=x){
int l=lower_bound(s+,s+n+,i)-s;
int r=upper_bound(s+,s+n+,i)-s;
tot+=r-l;
}
if(x*tot==n) return true;
else return false;
}
int main()
{
n=read();
if(n!=) ans++;
for(int i=;i<n;i++){
int x=read(),y=read();
add(x,y);add(y,x);
}
divide();
dfs(,);
sort(s+,s+n+);
for(int i=;i<=m;i++){
if(check(d[i])) ans++;
}
printf("%d\n",ans);
return ;
}
T1
T2:
题目大意:一个圆环上有N个数,将这N个数分为M个块,使得最大的块的和最小,输出这个最小值。
显然的单调性,二分答案。
对于圆环,短环成链并复制一倍。
关键点在于起始点的选择,$O(N)$枚举起始点再$O(N)$判断是绝对不可行的,我们需要优化。
我们可以优化判断,一般的判断方式是一个一个累加,直到大于二分的值位置,这个过程可以用倍增优化,设st[i][j]为以i为起点,长度为2j的区间和,从大到小枚举j,若加和小于二分的值,则累加。
时间复杂度$O(NM*log_2NM)$,M较大时有可能被卡掉。
还有一种思路是优化枚举起点。
我们先假设以0处为起始点,用$O(N)$的方法先找到此时的第一个块,也就是最靠左的块,并设这个块的左端点为L,右端点为R。
那么枚举的起始点只用在区间[L,R]内移动。
证明:
由于是圆环,所以从一个点向左右扩展都是可以的,如果以R+1为起始点,它可以向左扩展,其向左的第一个块必定为[L,R],与枚举起始点在L的情况重复了,所以不需要再枚举,其它点同理。
所以我们就在复杂度上除了一个M。
但是这个方法在一开始二分的值较大时会被卡成$O(N)$,所以在一开始要强化剪枝,一旦发现可行情况或发现不可行时要立即中止,才能保证算法的高效
时间复杂度$O((N^2log_2N)/M)$,M较小时会十分低效。
将两种思路综合起来就很难被卡掉了,或者可以测试点分治。我用的是第二种思路。
Code:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=;
int n,m,nn,L=,R=,ans;
int t[N<<];
bool judge(int y,int x)
{
int ans=,tot=;
for(int i=y;i<=y+n-;i++){
if(tot+t[i]>x){
ans++;tot=t[i];
}
else tot+=t[i];
if(ans>m) return false;
}
return true;
}
bool check(int x)
{
int l=,r=,tot=;
for(int i=;i<=n;i++){
if(tot+t[i]>x) break;
r=i;tot+=t[i];
}
for(int i=l;i<=r;i++){
if(judge(i,x)) return true;
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
nn=*n-;
for(int i=;i<=n;i++){
scanf("%d",&t[i]);
R+=t[i];L=max(L,t[i]);
}
for(int i=n+;i<=nn;i++)
t[i]=t[i-n];
ans=R;
while(L<=R){
int mid=(L+R)>>;
if(check(mid)){
ans=mid;
R=mid-;
}
else
L=mid+;
}
printf("%d\n",ans);
return ;
}
T2
T3:
详见洛谷1606白银莲花池。
我打的是BFS和DFS,用spfa也可以。
首先要求起点到终点的最短路径。我们发现移动一步的贡献不大于1,用不着最短路算法,一般的BFS可以解决。
但是此题有两种边权,0和1,并且0在使用一次后会变成1。
性质一:起点到终点的最短路中没有环。
证明一:环的权值不为负,所以走环之后步数不会少。
性质二:同一个点至多被经过一次。
证明二:若同一个点被经过多次,则一定存在环。
我们可以记录每个点是否被走过,然后就可以BFS了。
到现在这道题和算法竞赛进阶指南0x26中电路维修一样。可以用双端队列BFS解决,若到一个点的贡献为0,则从队头入队,反之从队尾入队。
问题一解决,现在求路径条数。
数据有问题,不过在作者和某NC的竭力hack,以及tdcp提供错误AC标程,该问题已被解决。
我们发现如果一个点被重复经过,会导致结果的错误,我们需要一个强有力的剪枝。
我们把从起点开始的求最短路BFS改为从终点开始,求出终点到所有点的最短距离,作为估价函数,搜索中一旦发现当前代价加估价大于最短路时,立即终止搜索,这样就可以防止重复了。
题目要求经过空格不同才算方案不同。
这个用BFS不好解决,我们可以嵌套DFS。
性质三:所有连通的敌人可以缩为一个点。
我们发现敌人就是一个中介点,由于敌人和方案数无关,它不能被入队,但是我们可以经过敌人到达其他的空地。
我没建边,所以用了鬼畜的DFS。
大框架还是BFS,每次对出队元素进行DFS,如果遇到敌人,则继续进行DFS,遇到空格就将其入队。
注意在同一次DFS中,更新节点的信息来源于同一个节点,所以一个点只能被更新一次。多次DFS之间,为防止重复,每个点只能入队一次。
BFS到最后,即为正确答案。
由于DFS的存在,时间复杂度$O(N^2M^2)$,但远远达不到这个上界。
Code:
#include<iostream>
#include<cstdio>
#include<queue>
#define LL long long
using namespace std;
const int N=;
int n,m,sx,sy,ex,ey;
int ans1=;
LL ans2=;
int a[N][N],v[N][N];
LL dp[N][N][N*N];
bool vis[N][N],in[N][N],out[N][N][N*N];
int dex[]={,,,,,-,-,-,-};
int dey[]={,,-,,-,,-,,-};
deque<int> q1,q2,q3;
void bfs1()
{
v[ex][ey]=;
q1.push_back(ex);q2.push_back(ey);
while(!q1.empty()){
int x=q1.front(),y=q2.front();
q1.pop_front();q2.pop_front();
for(int i=;i<=;i++){
int xx=x+dex[i],yy=y+dey[i];
if(a[xx][yy]==||xx<||xx>n||yy<||yy>m) continue;
if(v[xx][yy]!=) continue;
if(a[xx][yy]==){
v[xx][yy]=v[x][y];
q1.push_front(xx);q2.push_front(yy);
}
else{
v[xx][yy]=v[x][y]+;
q1.push_back(xx);q2.push_back(yy);
}
}
}
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
v[i][j]-=;
if(a[i][j]==) ans1=v[i][j];
}
}
}
void dfs1(int xx,int yy,int x,int y,int z)
{
vis[xx][yy]=true;
for(int i=;i<=;i++){
int nex=xx+dex[i],ney=yy+dey[i];
if(a[nex][ney]==||nex<||nex>n||ney<||ney>m) continue;
if(a[nex][ney]==){
if(v[nex][ney]+z>ans1) continue;
if(vis[nex][ney]) continue;
dfs1(nex,ney,x,y,z);
}
else{
if(v[nex][ney]+z+>ans1) continue;
if(in[nex][ney]) continue;
in[nex][ney]=true;
dp[nex][ney][z+]+=dp[x][y][z];
if(!out[nex][ney][z+]){
q1.push_back(nex);q2.push_back(ney);q3.push_back(z+);
out[nex][ney][z+]=true;
}
}
}
}
void dfs2(int x,int y,int z)
{
vis[x][y]=false;
for(int i=;i<=;i++){
int nex=x+dex[i],ney=y+dey[i];
if(a[nex][ney]==||nex<||nex>n||ney<||ney>m) continue;
if(a[nex][ney]==){
if(v[nex][ney]+z>ans1) continue;
if(!vis[nex][ney]) continue;
dfs2(nex,ney,z);
}
else{
if(v[nex][ney]+z+>ans1) continue;
in[nex][ney]=false;
}
}
}
void bfs2()
{
while(!q1.empty()){
q1.pop_back();q2.pop_back();
}
dp[sx][sy][]=;out[sx][sy][]=true;
q1.push_back(sx);q2.push_back(sy);q3.push_back();
while(!q1.empty()){
int x=q1.front(),y=q2.front(),z=q3.front();
out[x][y][z]=false;
q1.pop_front();q2.pop_front();q3.pop_front();
dfs1(x,y,x,y,z);
dfs2(x,y,z);
}
ans2=dp[ex][ey][ans1];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==){
sx=i;sy=j;
}
if(a[i][j]==){
ex=i;ey=j;
}
}
}
bfs1();
if(ans1==-){
printf("%d\n",ans1);
return ;
}
else
printf("%d\n",ans1-);
bfs2();
printf("%lld\n",ans2);
return ;
}
T3
NOIP模拟测试19的更多相关文章
- NOIP模拟测试19「count·dinner·chess」
反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...
- [考试反思]NOIP模拟测试19:洗礼
[]260 []230[]210 []200[8]170[9]160 这套题一般,数据很弱,T1T2暴力都能A,而且都是一些思维题,想不到就爆0. 原因不明,很多一直很强的人在这一次滑铁卢了,于是我个 ...
- NOIP模拟测试19考试反思
这次考试是存在很大问题的,(如果不是T1T2出乎意料地A了,鬼知道会发生什么) T2A是情理之中,考试的时候测的极限数据跑的很快(无论m什么范围),但是T1真的...... T3没有分配太多的时间+没 ...
- 2019.8.13 NOIP模拟测试19 反思总结
最早写博客的一次∑ 听说等会儿还要考试[真就两天三考啊],教练催我们写博客… 大约是出题最友好的一次[虽然我还是炸了],并且数据也非常水…忽视第三题的锅的话的确可以这么说.但是T3数据出锅就是你的错了 ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
随机推荐
- 前端导出excel表格
前言近期项目有个新需求--将折线图表的数据加一个下载成excel表格的功能.以前下载功能都是调后台接口的,但是这个迭代,后台压力比较重,部分就交给了前端自己实现,下面就记录一下前端如何实现excel表 ...
- docker 运行jenkins及vue项目与springboot项目(四.docker运行nginx)
docker 运行jenkins及vue项目与springboot项目: 一.安装docker 二.docker运行jenkins为自动打包运行做准备 三.jenkins的使用及自动打包vue项目 四 ...
- C/C++ C++ 11 std::move()
{ 0. C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意 是想把参数push_back进去就行 ...
- vim常用的骚操作
1.设置~/.vimrc syntax on 支持语法高亮 set nu 显示行号set nonu 不显示行号 set ai 设置自动缩进 set ...
- apue 第10章 信号signal
每种信号都有名字,都是以SIG开头 信号机制最简单的接口是signal函数 #include <signal.h> typedef void (*sighandler_t)(int); s ...
- 【Shiro】四、Apache Shiro授权
1.授权实现方式 1.1.什么是授权 授权包含4个元素(一个比较流行通用的权限模型) Resources:资源 各种需要访问控制的资源 Permissions:权限 安全策略控制原子元素 基于资源和动 ...
- MCS-51系列单片机和MCS-52系列单片机有何异同
MSC-51:1,片内4K字节程序存储器:2,片内128字节数据存储器:3,片内2个16位硬件定时器/计数器.MSC-52: 1,片内8K字节程序存储器:2,片内256字节数据存储器:3,片内3个16 ...
- thinkphp 连接多个数据库
config配置文件 //数据库配置信息 'DB_CONFIG' => array( 'DB_TYPE' => 'mysql', // 数据库类型 'DB_HOST' => 'loc ...
- CSS样式初始化代码
CSS样式初始化代码 为什么要初始化CSS? 建站老手都知道,这是为了考虑到浏览器的兼容问题,其实不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面差异.当然,初始化 ...
- Intellij IDEA 安装Scala插件 + 创建Scala项目
一.IDEA 2018 Ultimate edition (旗舰破解版下载地址) 百度网盘地址:https://pan.baidu.com/s/1d9ArRH6adhDUGiJvRqnZMw 二.I ...