这个是一个用单调栈的题目,至于为什么可以用单调栈?
把两个数组同时跑单调栈,如果每次进栈最多一个,当然在这个进栈之前肯定会有数出栈,
如果存在一个数进栈了,然后这个时候判断一下进栈的这个数的位置是不是相同,如果不相同就说明肯定是不对的。
为什么说这个时候只要考虑这个栈内的位置呢?
首先,这个最小值之前的数肯定是不要考虑的,因为当前的栈底就是目前位置最小的了,之后的数和之前的数RMQ函数返回的函数值肯定是这个栈底。
然后就是考虑栈内元素,这个应该很好想了。
#include <cstdio>//描述中的“如果找到,就说“X,let’s fly”(此处,X为开始时间)…" #include <cstdlib>//和Output中的 “X, let's fly” #include <cstring>//里的“ ’ ”和 “ ' ” 不是一个符号,别复制错了!!! #include <queue> #include <vector> #include <algorithm> #include <string> #include <stack> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1e5 + 10; typedef long long ll; int queue_mina[maxn]; int queue_minb[maxn]; int a[maxn], b[maxn]; int main() { int n; while(scanf("%d",&n)!=EOF) { bool flag = 1; int ans = n; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) scanf("%d", &b[i]); int f1 = 1, t1 = 0; int f2 = 1, t2 = 0; int r = 1; while(r<=n) { while (f1 <= t1 && a[r] < a[queue_mina[t1]]) t1--; queue_mina[++t1] = r; while (f2 <= t2 && b[r] < b[queue_minb[t2]]) t2--; queue_minb[++t2] = r; //printf("t1=%d t2=%d queue_mina[%d]=%d queue_minb[%d]=%d ", t1, t2, t1, queue_mina[t1], t2, queue_minb[t2]); if (t1 != t2) { flag = 0; ans = r - 1; break; } r++; } printf("%d ", ans); } return 0; }
这个题目是一个dp,现在看完题解之后感觉还比较好想,但是这个条件的判断我觉得还是比较难的。
就是判断哪一种一定不是答案
下面有两种写法,理解了任意一种另一种都可以很快的写出来
if(i-j>n||j-i>m)//为什么这么写就是对的呢? //因为i代表的是A的数量,j代表的是B的数量,如果A-B的数量大于n,就说明前面至少有n+1个A,这个B的数肯定 //有一部分在后面,所以这样的话AB的数量肯定>n,这样就不对了,后面的j-i>m 同理可得。 //这里可以筛出一部分肯定不对的,那么为什么满足这个就肯定是正确的呢。 //这个可以这么理解,这个if条件句把一定不对的筛出去了,如果后面有不合理的状态放到了dp数组里面 //最后一直往后走放A,B前面不合理的状态还是会被筛出去的 { dp[i][j] = 0; continue; }
这个是一种dp转移 dp[x][y]表示选了x个A,y个B的方案数
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1e5 + 10; typedef long long ll; const int mod = 1e9 + 7; ll dp[4400][4400]; int main() { int n, m; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<=n+m;i++) { for(int j=0;j<=n+m;j++) { dp[i][j] = 0; } } for(int i=0;i<=(n+m);i++) { for(int j=0;j<=(n+m);j++) { if(i-j>n||j-i>m)//为什么这么写就是对的呢? //因为i代表的是A的数量,j代表的是B的数量,如果A-B的数量大于n,就说明前面至少有n+1个A,这个B的数肯定 //有一部分在后面,所以这样的话AB的数量肯定>n,这样就不对了,后面的j-i>m 同理可得。 //这里可以筛出一部分肯定不对的,那么为什么满足这个就肯定是正确的呢。 //这个可以这么理解,这个if条件句把一定不对的筛出去了,如果后面有不合理的状态放到了dp数组里面 //最后一直往后走放A,B前面不合理的状态还是会被筛出去的 { dp[i][j] = 0; continue; } if (i == 0 || j == 0) dp[i][j] = 1; else dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod; } } printf("%lld ", dp[n + m][n + m]); } return 0; }
这个是dp[x][y]表示前面x个位置选了y个B的方案数
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1e5 + 10; typedef long long ll; const int mod = 1e9 + 7; ll dp[4400][4400]; int main() { int n, m; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<=2*(n+m);i++) { for(int j=0;j<=2*(n+m);j++) { dp[i][j] = 0; } } dp[0][0] = 1; if (n != 0) dp[1][1] = 1; if (m != 0) dp[1][0] = 1; for(int i=1;i<=2*(n+m);i++) { for(int j=0;j<=i;j++) { if(i-2*j>m||2*j-i>n) { dp[i][j] = 0; continue; } if (j == 0) dp[i][j] = 1; else dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % mod; } } printf("%lld ", dp[2 * (n + m)][n + m]%mod); } return 0; }