T1
题目大意:给定一个序列,求鸡尾酒排序需要进行多少次原序列有序
n
<
=
1
0
6
,
a
i
<
=
1
0
9
n<=10^6,a_i<=10^9
n<=106,ai<=109
题解:
考察的是对冒泡排序以及鸡尾酒排序原理的理解
模拟考试的时候还是卡了一会的
一个比较显然的推论:
我们确定一个分界线,对于前面的数中所有满足序列有序后在分界线后的点,每次鸡尾酒排序都至少有一个数字会被换到后面。反向也是同理。
然后只要统计所有分界线这个值得最大值即可
排序后依次插入位置,树状数组维护即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
int num = 0;char c = getchar();bool flag = true;
while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
if(flag) return num;else return -num;
}
int tr[1010000];
int n;
P a[1010000];
void add(int x,int v){for(int i=x;i<=n;i+=i&-i) tr[i]+=v;}
int query(int x){int sum=0;for(int i=x;i;i-=i&-i) sum+=tr[i];return sum;}
#define fr first
#define se second
int main()
{
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
n = rd();rep(i,1,n) a[i].fr = rd(),a[i].se = i;
sort(a+1,a+n+1);
int ans = 1;
rep(i,1,n-1)
{
add(a[i].se,1);
ans = max(ans,i-query(i));
}
printf("%d\n",ans);
return 0;
}
T2
题目大意:
给定n个点和m组限制
每组限制相当于是连一些有向边
求满足前x组限制的条件下字典序最小的拓扑序
满足限制的意思是无环
前提是x最大
n
<
=
1
0
5
,
m
<
=
5
∗
1
0
4
,
∑
m
i
<
=
2
∗
1
0
6
n<=10^5,m<=5*10^4,\sum m_i <= 2*10^6
n<=105,m<=5∗104,∑mi<=2∗106
题解:
显然答案具有单调性
每次二分,用拓扑序判断
最后输出的时候用单调队列即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
int num = 0;char c = getchar();bool flag = true;
while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
if(flag) return num;else return -num;
}
int n,m,linkk[101000],t;
struct node{int n,y,tim;}e[201000];
int tmp[201000],ans1;
bool vis[201000];
void insert(int x,int y,int z){e[++t].y = y;e[t].n = linkk[x];e[t].tim = z;linkk[x] = t;}
int du[101000];
struct cmp{
bool operator ()(int a,int b) {
return a>b;
}
};
priority_queue<int,vector<int>,cmp>q;
void tpsort()
{
rep(i,1,t) if(e[i].tim <= ans1) du[e[i].y]++;
rep(i,1,n) if(!du[i]) q.push(i);
int num = 0;
while(!q.empty())
{
int x = q.top();num++;q.pop();
if(num != n)printf("%d ",x);else printf("%d",x);
rept(i,x)
if(e[i].tim <= ans1)
{
int y = e[i].y;
du[y]--;
if(du[y] == 0) q.push(y);
}
}
}
queue<int>Q;
bool check(int mid)
{
rep(i,1,n) du[i] = 0;
rep(i,1,t) if(e[i].tim <= mid) du[e[i].y]++;
rep(i,1,n) if(!du[i]) Q.push(i);
while(!Q.empty())
{
int x = Q.front();Q.pop();
rept(i,x)
if(e[i].tim <= mid)
{
int y = e[i].y;
du[y]--;
if(du[y] == 0) Q.push(y);
}
}
rep(i,1,n) if(du[i] != 0) return false;
return true;
}
void work()
{
int l = 1,r = m;
while(l+1<r)
{
int mid = (l+r)>>1;
rep(i,1,n) vis[i] = false;
if(check(mid)) l = mid;
else r = mid;
}
rep(i,1,n) vis[i] = false;
if(check(r)) ans1 = r;
else
{
rep(i,1,n) vis[i] = false;
if(check(l)) ans1 = l;
else ans1 = 0;
}
if(ans1>0) tpsort();
else {rep(i,1,n-1) printf("%d ",i);printf("%d",n);}
}
int main()
{
freopen("milkorder.in","r",stdin);
freopen("milkorder.out","w",stdout);
n = rd();m = rd();
rep(i,1,m)
{
int x = rd();
rep(j,1,x) tmp[j] = rd();
rep(j,1,x-1) insert(tmp[j],tmp[j+1],i);
}
work();
return 0;
}
T3
题目大意:
给定
n
n
n个二元组
(
v
,
w
)
(v,w)
(v,w)和一个正整数
W
W
W
要求调出若干个二元组,在满足
∑
w
i
>
=
W
\sum w_i >= W
∑wi>=W的条件下最大化
∑
v
i
∑
w
i
\frac{\sum v_i}{\sum w_i}
∑wi∑vi
1
<
=
n
<
=
250
,
1
<
=
W
<
=
1
0
3
,
1
<
=
w
i
<
=
1
0
6
,
1
<
=
v
i
<
=
1
0
3
1<=n<=250,1<=W<=10^3,1<=w_i<=10^6,1<=v_i<=10^3
1<=n<=250,1<=W<=103,1<=wi<=106,1<=vi<=103
如果答案为实数x,要求输出
⌊
1000
x
⌋
\lfloor 1000x \rfloor
⌊1000x⌋
题解:
0/1分数规划模板题
用实数二分可能会有精度问题,当然卡的好还是能过去
题解给的做法是我们在
c
h
e
c
k
check
check的时候由于输出的要求,我们可以都乘上
1000
1000
1000的系数,然后用
0
/
1
0/1
0/1背包直接做
太水了没写代码