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的更多相关文章

  1. NOIP模拟测试19「count·dinner·chess」

    反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...

  2. [考试反思]NOIP模拟测试19:洗礼

    []260 []230[]210 []200[8]170[9]160 这套题一般,数据很弱,T1T2暴力都能A,而且都是一些思维题,想不到就爆0. 原因不明,很多一直很强的人在这一次滑铁卢了,于是我个 ...

  3. NOIP模拟测试19考试反思

    这次考试是存在很大问题的,(如果不是T1T2出乎意料地A了,鬼知道会发生什么) T2A是情理之中,考试的时候测的极限数据跑的很快(无论m什么范围),但是T1真的...... T3没有分配太多的时间+没 ...

  4. 2019.8.13 NOIP模拟测试19 反思总结

    最早写博客的一次∑ 听说等会儿还要考试[真就两天三考啊],教练催我们写博客… 大约是出题最友好的一次[虽然我还是炸了],并且数据也非常水…忽视第三题的锅的话的确可以这么说.但是T3数据出锅就是你的错了 ...

  5. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  6. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  7. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  8. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  9. NOIP模拟测试17&18

    NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...

随机推荐

  1. MySQL(关系型数据库管理系统)

    MySQL 关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL是最好的 RDBMS ...

  2. 使用Canvas操作像素

    现代浏览器支持通过<video>元素播放视频.大多数浏览器也可以通过MediaDevices.getUserMedia() API访问摄像头.但即使这两件事结合起来,我们也无法直接访问和操 ...

  3. 【Shiro】三、Apache Shiro认证

    配置好并获取到SecurityManager,代表Shiro正常运行起来了,可以使用Shiro的其它功能. 1.认证流程(API的使用流程) 认证的数据: Principals:标识 ·识别Subje ...

  4. 未来-YLB-跳蚤市场:跳蚤市场(flea market)

    ylbtech-未来-YLB-跳蚤市场:跳蚤市场(flea market) 跳蚤市场(flea market)是欧美等西方国家对旧货地摊市场的别称.由一个个地摊摊位组成,市场规模大小不等. 出售商品多 ...

  5. 3、jQuery面向对象

    1.首先介绍callback.js对ajax进行了封装 function ajaxFunction(){ var xmlHttp; try{ // Firefox, Opera 8.0+, Safar ...

  6. 怎么知道dll文件是哪个net版本

    有时候经常需要查看.dll所使用的.net版本, 因为根本不知道它是使用了1.1还是2.0, 或者是3.0, 这个时候如果需要打开vs.net那又太麻烦, 所以经过长久的摸索, 我找到了一个比较简便的 ...

  7. ORACLE切非归档模式:

    C:\Documents and Settings\Administrator>sqlplus /nologSQL> conn / as sysdbaConnected to an idl ...

  8. Python集成开发环境Pycharm+Git+Gitee(码云)

    ********************************************************************* 本文主要介绍集成开发环境的配置过程,方便多人协作办公.代码版 ...

  9. Java 实例 - 连接字符串

    以下实例演示了通过 "+" 操作符和StringBuffer.append() 方法来连接字符串,并比较其性能: StringConcatenate.java 文件 1 2 3 4 ...

  10. 执行sudo apt-get update报错

    1.在官网源https://mirrors.ustc.edu.cn/repogen/下载对应版本最新的源,比如我是16.04版本的ubuntu,对应下载的是这个 2.下载sources.list完成之 ...