基本思路就模拟整个过程,每次进行两两比较,赢得一分,输了的就不管。
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;
}
这道题刚刚拿着以为是一道关于位运算和搜索的题,然后不出所料的炸了。
好吧这题其实是一个动规题。
神奇的很。大千世界无奇不有,这不算什么。
比较难的地方在于:
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;
}