8.5牛客三水题
找了找A题比较多的牛客水体来做,还是挺困难
十字分布比较好判断
maxx,miny||minx,miny
————————————
maxx,maxy||minx,maxy
是这么的分布
所以只需要寻找有没有这样的点即可
那成四十五度歇着的框怎么办呢
原来只需要旋转一下,求出对应旋转后的坐标就好了
(x1,y1)为要转的点,(x2,y2)为中心点,如果是顺时针角度为θ,
x=(x1-x2)cosθ-(y1-y2)sinθ+x2
y=(y1-y2)cosθ+(x1-x2)sinθ+y2
假设对图片上任意点(x,y),绕一个坐标点(rx0,ry0)逆时针旋转a角度后的新的坐标设为(x0, y0),有公式:
x0= (x - rx0)*cos(a) - (y - ry0)*sin(a) + rx0 ;
y0= (x - rx0)*sin(a) + (y - ry0)*cos(a) + ry0 ;
/* Z市是一座港口城市,来来往往的船只依靠灯塔指引方向。 在海平面上,存在n个灯塔。每个灯塔可以照亮以它的中心点为中心的90°范围。 特別地, 由于特殊限制,每个灯塔照亮范围的角的两条边必须要么与坐标轴平行要么与坐标轴成45°。 由于经费限制,Z市的灯塔只能被点亮一座。你需要求出在这种情况下, 是否存在一座灯塔能够照亮Z市的所有灯塔。 输入描述: 第一行一个整数T,表示数据组数。 对于每组数据,第一行一个整数n,表示灯塔的数量。 接下来n行,每行两个整数xi,yi,表示第i座灯塔的坐标点。 输出描述: 如果存在一座灯塔能够照亮Z市的所有灯塔则输出Yes,否则输出No(区分大小写)。 示例1 输入 复制 2 4 1 1 1 2 2 1 2 2 5 4 7 0 4 7 3 3 0 3 4 输出 复制 Yes No 备注: n≤1000000,T≤10,0≤|xi|,|yi|≤109 */ #include <iostream> #include <cstdio> #include <string.h> #include <algorithm> using namespace std; int t,n; const int maxn = 1e6 + 5; struct node{ double x,y; }p[maxn]; bool check() { double minx = p[0].x,maxx = p[0].x; double miny = p[0].y,maxy = p[0].y; for(int i = 1;i < n;i++) { minx = min(minx,p[i].x); maxx = max(maxx,p[i].x); miny = min(miny,p[i].y); maxy = max(maxy,p[i].y); } for(int i = 0;i < n;i++) { if((p[i].x == minx || p[i].x == maxx )&&(p[i].y == miny || p[i].y == maxy)) return 1; } return 0; } int main() { scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i = 0;i < n;i++) scanf("%lf %lf",&p[i].x,&p[i].y); //正向判断 if(check()) { printf("Yes\n"); continue; } //斜着判断——转45度相对于原点 /* (x1,y1)为要转的点,(x2,y2)(0,0)为中心点,如果是顺时针角度为θ, x=(x1-x2)cosθ-(y1-y2)sinθ+x2 x = (x1-y1) * 二分之根二 y=(y1-y2)cosθ+(x1-x2)sinθ+y2 y = (x1+y1) * 二分之根二 因为xy都是扩展相同的倍数,对能够覆盖没有影响,所以不用乘以二分之根二 */ for(int i = 0;i < n;i++) { double nx = p[i].x - p[i].y; double ny = p[i].x + p[i].y; p[i].x = nx; p[i].y = ny; } if(check()) { printf("Yes\n"); } else { printf("No\n"); } } return 0; }
这个题还比较简单,任意子集的话就不用考虑很多啦,在开始点的上下左右有石头的话都为-1
如果没有石头那就确保指令的子集不能越界就好
如果别的行列有时候没有任何影响,因为你不能确保你的子集里有去别的行的指令
所以……
#include <iostream> #include <cstdio> #include <string.h> using namespace std; const int maxn = 60; char mp[maxn][maxn]; int main() { int t,n,m; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int x,y; for(int i = 0;i < n;i++) { scanf("%s",mp[i]); for(int j = 0;j < m;j++) { if(mp[i][j] == 'S') { x = i;y = j; } } } int f1,f2,f3,f4; f1 = f2 = f3 = f4 = 0; for(int i = x+1;i < n;i++) { if(mp[i][y] == '.') f1++; else{ f1 = -1; break; } } for(int i = x-1;i >= 0;i--) { if(mp[i][y] == '.') f2++; else{ f2 = -1; break; } } for(int i = y+1;i < m;i++) { if(mp[x][i] == '.') f3++; else{ f3 = -1; break; } } for(int i = y-1;i >= 0;i--) { if(mp[x][i] == '.') f4++; else{ f4 = -1; break; } } if(f1 == -1 || f2 == -1 || f3 == -1 || f4 == -1) { //cout<<f1<<" "<<f2<<" "<<f3<<" "<<f4<<endl; puts("-1"); } else { printf("%d\n",f1+f2+f3+f4); } } return 0; }
还真不是个大水题,也不一定,没见过这类型的
想到了map和线性dp就好做了
对于sum求值用前缀和来进行优化
对于当前元素dp[i]初始赋值dp[i-1]
如果i元素前面有元素出现位置是j
优化dp[i] = max(dp[i],dp[j-1] + sum[j] - sum[j-1])
嗯所以有点类似链式前向星来记录前继点,但是数据较大,所以用map标记来做,真的很妙啊
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <map> using namespace std; const int maxn = 3e5 + 100; typedef long long ll; ll sum[maxn],dp[maxn],g[maxn]; map<ll,ll> mp; int a[maxn],pre[maxn]; int main() { int n; scanf("%d",&n); //memset(pre,0,sizeof(pre)); //mp.clear(); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); pre[i] = mp[a[i]]; mp[a[i]] = i; } //cout<<pre[3]<<endl; for(int i = 1;i <= n;i++) { scanf("%lld",&g[i]); if(i == 1)sum[i] = g[i]; else sum[i] = sum[i-1] + g[i]; } dp[1] = 0; dp[0] = 0; for(int i = 2;i <= n;i++) { dp[i] = dp[i-1]; int j = pre[i]; while(j) { dp[i] = max(dp[i],sum[i] - sum[j-1] + dp[j-1]); if(dp[i] == sum[i])break; j = pre[j]; } } printf("%lld\n",dp[n]); return 0; }