E. Polygon
给定一个数 n,生成一个 n×n 的一个全为 0 的初始矩阵,矩阵上方和左方均有一排炮台,矩阵的下边和右边是边界
炮台可以发射子弹,子弹只能直线行走,且遇到边界后会停止,遇到一个停止的子弹也会停止,子弹停止后的坐标里面的值记为 1
在任何时候,都不会有超过一门大炮在射击
输入
第一行一个整数 \(t\),表示数据组数
对于每组数据:
第一行一个整数 n
接下来是 n个长度为 n 的行,由 0 和 1组成,表示输入矩阵
所有测试案例中矩阵的总面积不超过\(10^5\)
输出
存在\(YES\),不存在\(NO\)
Example
Input
5
4
0010
0011
0000
0000
2
10
01
2
00
00
4
0101
1111
0101
0111
4
0100
1110
0101
0111
Output
YES
NO
YES
YES
NO
注意
第一个测试用例在声明中已经解释过了
第二个测试用例的答案是否定的,因为从任何大炮中飞出的单元格 ( \(1, 1\) ) 中的 1 都会继续飞行
炮弹遇到边界后会停止,遇到一个停止的子弹也会停止,我们可以知道当下方和右方的地方都为 0 是不可能停下的
于是就可以检查矩阵中的元素,其下一个和右侧不能同时为 0
出现这种情况就不满足条件,则是 "NO"
[!NOTE]
本来不是这题的,其实昨天就已经写好了今天的,但是今天醒来发现居然和学长撞题了算了还是把昨天写的放一下尾页吧
,又挑了几题普及+的题发现一直不能完全过,红温了,于是在cf上找了一道1300的题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;ll gcd(ll p, ll q) {return ((p % q == 0)? q : gcd(q, p % q));}
ll lcm(ll p, ll q) {return p * q / gcd(p, q);}void solve(){int n;cin >> n;int a[n][n];bool ans = true;for (int i = 0; i < n; ++i) {string s;cin >> s;//转换为整数存储在数组中for (int j = 0; j < s.size(); j++) a[i][j] = s[j] - '0'; }for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - 1; j++) {if (a[i][j] == 1) {//当前元素是1,则检查下方和右方的元素if (a[i + 1][j] == 0 && a[i][j + 1] == 0) {//如果下方和右方都是0,则NOans = false;break;}}}}if (ans) cout << "YES" << endl;else cout << "NO" << endl;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}
P1725 琪露诺
在幻想乡,琪露诺是以笨蛋闻名的冰之妖精 \((baka)\)
某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸。于是琪露诺决定到河岸去追青蛙
小河可以看作一列格子依次编号为 \(0\) 到$ N$,琪露诺只能从编号小的格子移动到编号大的格子。而且琪露诺按照一种特殊的方式进行移动,当她在格子 \(i\) 时,她只移动到区间 \([ i+L,i+R ]\) 中的任意一格。你问为什么她这么移动,这还不简单,因为她是笨蛋啊$ (baka)$
每一个格子都有一个冰冻指数 \(Ai\),编号为 \(0\) 的格子冰冻指数为$ 0$。当琪露诺停留在那一格时就可以得到那一格的冰冻指数 \(Ai\)。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,这样她才能狠狠地教训那只青蛙
但是由于她实在是太笨了,所以她决定拜托你帮它决定怎样前进
开始时,琪露诺在编号$ 0 \(的格子上,只要她下一步的位置编号大于\) N$就算到达对岸
输入格式
第一行三个正整数$ N,L,R$
第二行共 $N+1 \(个整数,第\) i$个数表示编号为 \(i−1\) 的格子的冰冻指数 \(Ai−1\)
输出格式
一个整数,表示最大冰冻指数
样例
输入
5 2 3
0 12 3 11 7 -2
**输出 **
11
说明/提示
对于 \(60\)%的数据,\(N≤10^4\)
对于 \(100\)%的数据,\(N≤2×10^5\),\(−10^3≤Ai≤10^3\),\(1≤L≤R≤N\)
数据保证最终答案不超过\(2e31 −1\)
歌词大意:
小河为编号\(0\)从到\(N\)的格子序列,\(baka\)从\(0\)号格出发,只能向编号更大的格子移动,且每次移动范围在当前格编号\(i\)的\([ i+L,i+R ]\) 区间内
每个格子有冰冻指数\(Ai\),\(0\)号格冰冻指数为\(0\),\(baka\)停留在某格可获取其冰冻指数
求\(baka\)到达对岸(下一步的位置编号大于$ N$)时能获得的最大冰冻指数
由题易知用线性\(dp\),\(f[i]\)表示到第\(i\)个点为止所能获得的最大收益 则\(f[i]=a[i]+max(f[i−r],...,f[i−l])\)
但是复杂度为\(O(n^2)\),还是不能AC
因此我们需要好好优化一下~~❤❤❤
由标签可知主要可以用单调队列优化(单调队列来解决的问题一般都是需要得到当前的某个范围内的最小值或最大值)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//const int N = 2e5 + 10;
ll gcd(ll p, ll q) {return ((p % q == 0)? q : gcd(q, p % q));}
ll lcm(ll p, ll q) {return p * q / gcd(p, q);}void solve(){int n, l, r, baka = -INT_MIN;cin >> n >> l >> r;vector<int> a(n + 1),f(n + 1);deque<int> q;//双端队列//或者vector<int> q;for (int i = 0; i <= n; i++) {cin >> a[i];f[i] = baka;//确保其他初始值足够小}f[0] = 0;//空区间的和为0,确保能正确累加子区间和for (int i = l; i <= n; i++) {//移除不在窗口[i-r, i-l]内的元素while (!q.empty() && q.front() + r < i) {q.pop_front();//或者q.erase(q.begin());}while (!q.empty() && f[q.back()] <= f[i - l]) {//使头部始终是当前窗口内f值最大的索引(维护双端队列)q.pop_back();}q.push_back(i - l);///存入i-l到末尾f[i] = f[q.front()] + a[i];//以i结尾的最大子区间和if (i + r > n) baka = max(baka, f[i]);}cout << baka << endl;}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);//int t;cin >> t;while (t--) {solve();//}return 0;
}