10.7离线赛
来源:互联网 发布:单片机呼吸灯 编辑:程序博客网 时间:2024/05/29 18:47
预分240 实分240
一、S数
应得100 实得100
题意:在[l,r]区间内求满足S(x*x)=S(x)^2的数的个数,S(x)=x各位数字和
数据:对于80%,r∈[1,1e5]
对于100%,r∈[1,1e9],l<=r
80%的只需要一个循环打过去就可以了。
然后把表打出来,发现满足的x只由0123四个数字组成,按照这四个数字造数,共4^9=262144个,dfs一下就过了。
当然这不是正解。发现S(x*x)的最大值是18 * 9,那S(x)的最大值约为12,然后按照各位数字和为12去dfs即可。
二、黑客入侵
应得100 实得100
题意:有n个坦克在一条直线,每个坦克有一个坐标和射程,从右往左轮流开炮,若还在就开炮打毁所有射程内的坦克。有一个备用坦克可以摧毁从右往左连续的任意数量的坦克。求最少损失量。
数据:对于70%,n∈[1,2000]
对于100%,n∈[1,200000],射程和位置∈[1,1e9]
对于70%只要枚举一下最右边要打毁几座坦克,然后再循环一遍,这样是O(N^2)。
正解dp
我写的是两维。
dp[i][0] 表示第i个坦克被摧毁时最多存活几个
dp[i][1] 表示第i个坦克打别人时最多存活几个
那么dp[i][0] 就是从dp[i-1][0] 和 dp[i-1][1] 中取最大值
dp[i][1] 就是dp[x-1][1]+1 x是不会被i打到的最靠右的坦克,二分一下就行
为什么是dp[x-1][1] 呢?因为只要活着就必须打,按照题意。
另一种是用一维的。这样就不用管到底打还是没打,转移就是dp[i]=i-x+dp[x-1]。(来自于JRH大佬)
x与我的是一样的。但是注意这里的dp是最少的摧毁个数,而不是存活个数
连个代码均贴上
二维的:
#include<bits/stdc++.h>#define M 200005using namespace std;int A[M],S[M],dp[M][2],n;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&A[i],&S[i]); for(int i=1;i<=n;i++){ int x=lower_bound(A,A+1+n,max(0,A[i]-S[i]))-A;//二分查找,手打比函数快,这里为了方便,能A就行 dp[i][0]=max(dp[i-1][0],dp[i-1][1]); dp[i][1]=dp[x-1][1]+1; } printf("%d\n",min(n-dp[n][0],n-dp[n][1])); return 0;}
一维的
#include<cstdio>#include<algorithm>using namespace std;int pos[200005],A[200005],dp[200005],n,ans=2e9;int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d %d",&pos[i],&A[i]); int x=lower_bound(pos+1,pos+1+i,pos[i]-A[i])-pos; A[i]=x; } for(int i=1; i<=n; i++) { dp[i]=i-A[i]+dp[A[i]-1]; if(dp[i]+n-i<ans)ans=dp[i]+n-i; } printf("%d",ans); return 0;}
三、炮兵阵地
应得40 实得40
题意:司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
数据:如图所示
来源:NOI2001复赛
状压dp的一道入门题(虽然我想了很久)。考试时我想了一个O(N*M)的完全错误代码,还过了测试数据,发现是凑出来的……dfs里加了一个cnt计算运行次数,若cnt>=100000000(1e7)就直接输出。这是dfs水分利器。
正解:dp[i][j][k] 表示第i行用第j种方案,第i-1行用第k种方案时的最大炮兵放置数。这样看肯定是一头雾水。下面向详细分析:
1、方案数:因为列数都小于10,那就可以用位运算把哪些点放炮兵,哪些不放表示出来。2^10是1024,这样数组岂不是开不下?实际上只有60多种情况,因为很多情况都会重复或者不符合,到时程序有注释。
2、放置数:这是在预处理方案数时对于每一个方案的炮兵放置数量。
3、炮兵攻击范围是两格,为什么只要枚举i-1层,而不用i-2层呢?其实是要的,但是没有放在dp下标里。在转移时要多加一条判断。
还要注意因为转移时要用到i-1和i-2层,所以第一层和第二层是需要单独处理的。相邻三层的方案不能一样,否则会互相打到。
#include<bits/stdc++.h>using namespace std;char sca[105];int A[105][15],num[105],dp[105][65][65],s1[105],Gs,G[105];int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ scanf("%s",sca); for(int j=0;j<m;j++) if(sca[j]=='H')num[i]+=(1<<j);//把高地放在相应的位置 } for(int i=0;i<(1<<m);i++){ if(i&i<<1)continue; if(i&i<<2)continue; int now=i; while(now){ s1[Gs]+=now&1;//此状态的炮兵个数 now>>=1; } G[Gs++]=i;//状态 } for(int i=0;i<Gs;i++)//第一行的dp值(这里是0) if(!(G[i]&num[0]))dp[0][i][0]=s1[i]; for(int i=0;i<Gs;i++)//第二行的dp值(这里是1) if(!(G[i]&num[1])) for(int j=0;j<Gs;j++){ if((G[j]&G[i])||G[j]&num[0])continue;第二行与第一行方案数不能相同。第二行这个点不是山 dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+s1[i]);//第一行的方案数加上第二行的方案数 } for(int i=2;i<n;i++) for(int j=0;j<Gs;j++){//第i行的方案 if(G[j]&num[i])continue;//第i行这个点不是山 for(int k=0;k<Gs;k++){//第i-1行的方案 if((G[j]&G[k])||(G[k]&num[i-1]))continue;//第i行与第i-1行的方案数要不一样 for(int l=0;l<Gs;l++){//第i-2行的方案 if((G[k]&G[l])||(G[l]&G[j])||(G[l]&num[i-2]))continue; //第i-2与第i-1行方案数不一样,第i-2与第i行方案不一样,第i-2行不是山 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+s1[j]); } } } int ans=0; for(int i=0;i<Gs;i++) for(int j=0;j<Gs;j++) if(!(G[i]&G[j]))ans=max(ans,dp[n-1][i][j]); printf("%d\n",ans); return 0;}
实际上很简单的一道题,只是想得太浅了。
- 10.7离线赛
- 10.26离线赛题解
- 天池离线赛
- 天池离线赛
- 天池离线赛
- 天池离线赛
- 10.3离线赛
- 10.4离线赛
- 离线赛20171004总结
- 10.6离线赛
- 离线赛20171006总结
- 20171006离线赛总结
- 20171007离线赛总结
- 离线赛20171007总结
- 10.8离线赛
- 离线赛20171008总结
- 离线赛20171008总结
- 离线赛总结
- Ajax的使用
- AI基本术语笔记
- 算法~快速排序~体会
- Iron and Coal
- 交叉熵、L2规范化、权重初始化推导,改进Michael Nielsen神经网络(2)
- 10.7离线赛
- Golang json用法详解
- C++之数据对齐
- 手机网上商城-项目经验总结(十)-自动登录
- hdoj 6215 Brute Force Sorting
- ios-SDWebImage的一些实现机制
- Codeforces 101490E Charles in Charge
- 1738. Heatwave
- 关于校正网络