noip模拟题 小奇2 by hzwer[DP][路径压缩][分类讨论][位运算]

2024-01-01 07:59

本文主要是介绍noip模拟题 小奇2 by hzwer[DP][路径压缩][分类讨论][位运算],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这么颓下去,迟早要完。

这套题只考了2h,感觉还不错,T2做过类似的所以A了,T1和T3基本上也没什么大问题,关键就是要深入挖掘问题特质,学会分类讨论(很多题都可以剪掉大量的枝,比如T1,小奇1的T3,noip2015 day1 T3,都是需要有这种分类意识的。
T1:
题意:在坐标轴上有一些点有收益,问从0开始,每次只能向前跳4(0+4=4)步或7(0+7=7)步,最大收益是。
数据范围:
对于20%的数据n=1,m<=10^5
对于40%的数据n<=15,m<=10^5
对于60%的数据m<=10^5
对于100%的数据n<=10^5,m<=10^9,1<=ai<=10^4,1<=bi<=m
分析:
感觉这道题是数据分斥(还是什么,不知道叫什么)的典型例子,黄学长这两套题出的还是不错的。
20%n=1,只用看能不能去就行了。
60%的数据,m比较小,可以f[i]表示i这个位置的最大值,那么然后去找-4,-7的最大值就可以了。
100%,经过分析发现,>=18的情况是一定可以走到的!那么就可以18以内用数组存能不能走,18以外都可以走,在走的时候更新18以内的最大值就可以了!
下面是碎碎念可以不看:
关键就是发现>=18的那个性质,这个要求我们多手算找规律啊。
按理说发现>=18以后一百分算法应该顺理成章不过我居然没发现,还是没养成这种意识。
而且考这套题的时候太zz了,因为我的算法应该是40分,我想了很久后面那20分怎么拿,结果拿到解题报告才想起来,枚举m的话时间复杂度线性……

60分程序:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "mining"
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,ans,f[Maxn];
struct node
{int a,b;
}a[Maxn];
bool cmp(node x,node y)
{return x.a<y.a;
}
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*10+ch-'0';ch=getchar();}return x*f;
}
void init()
{n=read();m=read();each(i,n){a[i].b=read();a[i].a=read();}sort(a+1,a+n+1,cmp);
}
int boo[20]={1,0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1};
int check(int cur,int pre)
{if(cur-pre>=18)return 1;return boo[cur-pre];
}
void work()
{for(int i=1;i<=n;i++){int j=i-1;int flg=1;for(;j>=0;j--)if(check(a[i].a,a[j].a))f[i]=max(f[j]+a[i].b,f[i]);ans=max(ans,f[i]);}printf("%d",ans);
}
void debug()
{//
}
int main()
{freopen("hop.in","r",stdin);freopen("hop.out","w",stdout);init();work();//debug();return 0;
}

100分:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "mining"
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,ans,maxn,f[Maxn];
struct node
{int a,b;
}a[Maxn];
bool cmp(node x,node y)
{return x.a<y.a;
}
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*10+ch-'0';ch=getchar();}return x*f;
}
void init()
{n=read();m=read();each(i,n){a[i].b=read();a[i].a=read();}sort(a+1,a+n+1,cmp);
}
int boo[20]={1,0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1};
int check(int cur,int pre)
{if(cur-pre>=18)return 1;return boo[cur-pre];
}
void work()
{for(int i=1;i<=n;i++){int j=i-1;for(;j>=max(0,i-17);j--)if(check(a[i].a,a[j].a))f[i]=max(f[j]+a[i].b,f[i]);if(i>18)maxn=max(maxn,f[i-18]);if(check(a[i].a,0))f[i]=max(f[i],maxn+a[i].b);ans=max(ans,f[i]);}printf("%d",ans);
}
void debug()
{//
}
int main()
{freopen("hop.in","r",stdin);freopen("hop.out","w",stdout);init();work();//debug();return 0;
}

T2:
题意:从带权矩阵左上角走到右下角(只能向下或向右走),求 (n+m1)Σn+m1i=1(AiAavg)2 的最小值.
分析:首先呢我们可以证明对于一个序列,若平均值错误,V值一定更小(具体怎么证?考虑一个长度为2的序列,把它拆开,看一下,这不是均值不等式吗)。
然后,你看这权值范围<=30,一看就可以做奇怪的事。根据最小精度枚举平均值情况就可以了。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1,i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC ""
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=305;
int t,n,m,lim,limi,ans,a[Maxn][Maxn],f[Maxn][Maxn];
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*10+ch-'0';ch=getchar();}return x*f;
}
void init()
{n=read();m=read();lim=n+m-1;for(int i=2;i<=n;i++)f[i][0]=inf;for(int j=2;j<=m;j++)f[0][j]=inf;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read()*lim;limi=lim*30;ans=2e9;
}
void work()
{for(int i=lim;i<=limi;i++){for(int j=1;j<=n;j++)for(int k=1;k<=m;k++)f[j][k]=min(f[j][k-1],f[j-1][k])+(a[j][k]-i)*(a[j][k]-i);ans=min(ans,f[n][m]);}printf("%d\n",ans/lim);
}
void debug()
{//
}
int main()
{freopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);t=read();for(int i=1;i<=t;i++){init();work();}//debug();return 0;
}

T3:
题意:对于一棵树,对于每个点,求其他点到这个点的距离分别异或一值的和。
分析:
其实吧,多法图你就会发现,这个东西,其实可以通过统计最后几位的01来解决。具体的实现就是,用处理0那种情况(也就是两次dfs记两个数组)的方法,再同时处理个01就可以了,然而我当初太天真,写了个暴力。
碎碎念:多fa图。
暴力:(好像m!=0处理有错WA了一组,求大神指点。)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC ""
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,a,b,ans,roa[Maxn],g[Maxn],son[Maxn];
int f[Maxn],fr[Maxn],tov[2*Maxn],des[2*Maxn],wor[2*Maxn];
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*10+ch-'0';ch=getchar();}return x*f;
}
void addedge(int cur)
{a=read();b=read();wor[2*cur]=wor[2*cur-1]=read();tov[2*cur-1]=fr[a];fr[a]=2*cur-1;des[2*cur-1]=b;tov[2*cur]=fr[b];fr[b]=2*cur;des[2*cur]=a;
}
void dfs(int u,int fath,long long dis)
{if(dis)ans+=dis^m;for(int i=fr[u];i;i=tov[i])if(des[i]!=fath)dfs(des[i],u,dis+(long long)wor[i]);
}
void dfs2(int u,int fath)
{for(int i=fr[u];i;i=tov[i])if(des[i]!=fath){dfs2(des[i],u);roa[des[i]]=wor[i];son[u]+=1+son[des[i]];f[u]+=f[des[i]]+wor[i]*(son[des[i]]+1);}
}
void dfs3(int u,int fath)
{g[u]=f[fath]-f[u]+g[fath]+roa[u]*(n-son[u]*2-2);for(int i=fr[u];i;i=tov[i])if(des[i]!=fath)dfs3(des[i],u);
}
void init()
{n=read();m=read();for(int i=1;i<n;i++)addedge(i);
}
void work()
{if(m){for(int i=1;i<=n;i++){ans=0;dfs(i,0,0LL);printf("%d\n",ans);}}else{dfs2(1,0);f[0]=f[1];dfs3(1,0);for(int i=1;i<=n;i++)printf("%d\n",f[i]+g[i]);}
}
void debug()
{//
}
int main()
{freopen("tree1.in","r",stdin);freopen("tree1.out","w",stdout);init();work();//debug();return 0;
}

这篇关于noip模拟题 小奇2 by hzwer[DP][路径压缩][分类讨论][位运算]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/558603

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu2544(单源最短路径)

模板题: //题意:求1到n的最短路径,模板题#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#i

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b