维护一个栈的二分写法
题意:
有n个事件,现在给出每一个事件发生的次序。然后让你给学生自己写的答案打分,学生的答案就按照第二种给分的方式。也就是找出学生的答案在正确答案的相对正确的数目最多有多少个!
思路:
虽然题目的输入有点绕,但是只要找到所要求的答案就行。显然要找到学生的答案在正确答案的序列中出现的位置。保存每一个事件的正确位置。然后每当学生的第i个答案选出,就把第i个答案的正确位置赋值给它,
这意味着,学生的每一个选项都会有对应位置,我们只要找到最大递增子序列就行。
其实还有一种解法是转化为原来的次序然后求出公共子序列。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 100;
int n;
int s[maxn];
int a[maxn],b[maxn];
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i = 1;i <= n; i++) {
int temp;
scanf("%d",&temp);
a[i] = temp;
}
int t;
while(scanf("%d",&t) != EOF) {
b[t] = a[1];
for(int i = 2;i <= n; i++) {
int temp;
scanf("%d",&temp);
b[temp] = a[i];
}
memset(s,0,sizeof(s));
s[0] = -1;
int len = 0;
for(int i = 1;i <= n; i++) {
if(b[i] > s[len]) {
s[++len] = b[i];
}
else {
int l = 1,r = len;
while(l < r) {
int mid = (l + r) >> 1;
if(s[mid] < b[i])
l = mid + 1;
else
r = mid;
}
s[l] = b[i];
}
}
printf("%d\n",len);
}
return 0;
}
- 这道题比较难理解的就是输入的转换,其实可以直接还原答案的原来位置,然后把其中正确的答案做映射,然后计算出学生在映射下的递增序列的长度。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000;
int n;
int a[maxn],b[maxn];
int A[maxn];
int s[maxn];
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i = 1;i <= n; i++) {
int temp;
scanf("%d",&temp);
a[temp] = i;
}
for(int i = 1;i <= n; i++) {
A[a[i]] = i;
}
int t,temp;
while(scanf("%d",&t) != EOF) {
b[t] = 1;
for(int i = 2;i <= n; i++) {
scanf("%d",&temp);
b[temp] = i;
}
memset(s,0,sizeof(s));
s[0] = -1;
int len = 0;
for(int i = 1;i <= n; i++) {
int t = A[b[i]];
if(t > s[len]) {
s[++len] = t;
}
else {
int l = 1,r = len;
while(l < r) {
int mid = (l + r) >> 1;
if(t > s[mid])
l = mid + 1;
else
r = mid;
}
s[l] = t;
}
}
printf("%d\n", len);
}
return 0;
}