3月27日 题解


基本思路就模拟整个过程,每次进行两两比较,赢得一分,输了的就不管。

sort其实就是快速排序,而快速排序其实就是二分的思想。稳定的话O(nlogn)左右。但是仔细想想此题——每次需要更新的值,都是相邻两个人变化后的分数;而相邻的分数,有些是不会改变位置的,而快速排序则是每次全部修改,必然会造成浪费。

虽然很慢但是可能这种暴力也应该会打那我就放在这:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define In(x) scanf("%d",&x)
const int MAXN = 1e5 + 5;
const int wei = 20;
int a[2*MAXN];
int v[2*MAXN];
int n,m,q;
struct 	A
{
	int pos;
	int a;
	int v;
	bool operator < (const A y) const
	{
		if(a > y.a) return true;
		if(a == y.a) return pos < y.pos;
		return false;
	}
}p[MAXN*2];
//int ans = 0,pos;
//bool first = 0;
void work(int step)
{
	if(step == 0) return;
	sort(p,p+2*n);
	for(int i = 0;i < 2*n;i += 2)
	{
		if(p[i].v > p[i + 1].v) p[i].a++;
		else p[i + 1].a++;
	}
	step--;
	work(step);
}
int main()
{
//	freopen("swiss.in","r",stdin);
//	freopen("swiss.out","w",stdout);
	In(n);
	In(m);
	In(q);
	for(int i = 0;i < 2*n;i++)
	{
		In(p[i].a);
		p[i].pos = i + 1;
	}
	for(int i = 0;i < 2*n;i++)
	{
		In(p[i].v);
	}
	work(m);
	sort(p,p+2*n);
//	cout << p[q - 1].a << endl;
//	for(int i = 0;i < 2*n;i++)
//		cout << p[i].a << endl;
	printf("%d",p[q - 1].pos);
	return 0;
}

另一个思路:

用归并排序,给出俩数组+一个temp暂存数组,俩数组一个存胜者(win),另一个存负者(loser),因为这道题的两两相比的性质使其具有优越性,就不会浪费快排那每次都要判断改变位置的时间。用a数组(即为temp暂存数组)来记录每次胜者和负者的下标,并且根据归并排序过程每次排好序,便于下次使用。这样r轮过后就可以得到答案a[q]。

#include<bits/stdc++.h>
using namespace std;
#define lenw win[0] 
#define lenl loser[0] 
#define lena a[0] 
const int MAXN = 1e6 + 5;
int n,r,q;
int win[2*MAXN],loser[2*MAXN];
int a[MAXN*2],s[MAXN*2],w[MAXN*2];
bool cmp(int x,int y)
{
	if(s[x] == s[y]) return x < y;
	return s[x] > s[y];
} 
void merge()
{
	int i,j;
	i = j = 1;
	lena = 0;
	while(i <= lenw && j <= lenl)
	{
		if(cmp(win[i],loser[j]))
			a[++lena] = win[i++];
		else
			a[++lena] = loser[j++];
	}
	while(i <= lenw)  a[++lena] = win[i++];
	while(j <= lenl) a[++lena] = loser[j++];
}
int main()
{
	scanf("%d %d %d",&n,&r,&q);
	n*=2;
	for(int i = 1;i <= n;i++)
	{
		a[i] = i;
		scanf("%d",&s[i]);
	} 
	for(int i = 1;i <= n;i++) scanf("%d",&w[i]);
	sort(a+1,a+n+1,cmp);
	for(int i = 1;i <= r;i++)
	{
//		win[0] = lose[0] = 0;
		lenw = lenl = 0;
		for(int j = 1;j <= n;j+=2)
		{
			if(w[a[j]] > w[a[j+1]])
			{
				s[a[j]]++;
				win[++lenw] = a[j];
				loser[++lenl] = a[j+1];
			}
			else
			{
				s[a[j+1]]++;
				win[++lenw] = a[j + 1];
				loser[++lenl] = a[j];
			} 
		}
		merge();
	} 
	cout << a[q];
	return 0;
}

这道题刚刚拿着以为是一道关于位运算和搜索的题,然后不出所料的炸了。

扫描二维码关注公众号,回复: 1624439 查看本文章

好吧这题其实是一个动规题。

神奇的很。大千世界无奇不有,这不算什么。

比较难的地方在于

1.有优先级

2.有括号

总的来说就是老生常谈的表达式求值问题。

那么我们就进行优先级处理就好了。

我们用了一个STL的结构体模板 pair<int,int> Srt; 相当于开了一个有俩int类型变量的结构体,他们一个叫first,一个叫second,直接当结构体用就行了。

make_pair(1,1)意为返回一个first = 1,second = 1的结构体。

具体的我们用p数组来保存每个右括号对应的左括号位置,用stack a来保存右括号位置编号。这样一一对应,我们在处理括号时会方便许多。

然后为了节约时间,用了一个二分来处理字符(但是可能是数据量比较小吧我居然还比他们一个个枚举的慢),我们从右往左找

一个括号或是一个运算符,以优先级从低到高进行板块分割递归。遇见右括号就拿到左括号位置,然后找到第一个不在括号内的运算符,递归成板块。因为要把全部都找一遍,总能把每个括号里的东西都成块,最后递归dp出最多的种数。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
#define MOD 10007
typedef pair<int,int> Srt;
int l,p[MAXN];//p保存每个右括号对应的左括号位置 
char s[MAXN];
stack<int> a;//左括号栈 

Srt calc(Srt a,Srt b,char c)  
{  
  Srt so;  
  if (c=='+')  
  {  
    so.first=(a.first*b.first)%MOD;  
    so.second=((a.first*b.second)%MOD+(a.second*b.first)%MOD+(a.second*b.second)%MOD)%MOD;  
  }  
  else  
  {  
    so.first=((a.first*b.first)%MOD+(a.second*b.first)%MOD+(a.first*b.second)%MOD)%MOD;  
    so.second=(a.second*b.second)%MOD;  
  }  
  return so;  
}  
Srt f(int l,int r)
{
	int i;
	if(l > r) return make_pair(1,1);
	for(i = r;i >= l;i--)
	{
		if(s[i] == ')') i = p[i];
		if(s[i] == '+') break;
	}
	if(i < l)
	{
		for(i = r;i >= l;i--)
		{
			if(s[i] == ')') i = p[i];
			if(s[i] == '*') break;
		}
	}
	else
	{
		Srt x,y;
		x = f(l,i - 1);
		y = f(i + 1,r);
		return calc(x,y,'+');
	}
	if(i < l) return f(l + 1,r - 1);
	else{
		Srt x,y;
		x = f(l,i - 1);
		y = f(i + 1,r);
		return calc(x,y,'*');
	}
}

int main()
{
	scanf("%d",&l);
	scanf("%s",s);
	
	for(int i = l - 1;i >= 0;i--)
	{
		if(s[i] == ')') a.push(i);
		if(s[i] == '(') 
			p[a.top()] = i,a.pop();
	}
	
	printf("%d",f(0,l - 1).first % MOD);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/79746060
今日推荐