2018US Open Contest gold 題解
阿新 • • 發佈:2018-12-14
T1
題目大意:給定一個序列,求雞尾酒排序需要進行多少次原序列有序
題解: 考察的是對氣泡排序以及雞尾酒排序原理的理解 模擬考試的時候還是卡了一會的 一個比較顯然的推論: 我們確定一個分界線,對於前面的數中所有滿足序列有序後在分界線後的點,每次雞尾酒排序都至少有一個數字會被換到後面。反向也是同理。 然後只要統計所有分界線這個值得最大值即可
排序後依次插入位置,樹狀陣列維護即可
#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最大
題解: 顯然答案具有單調性 每次二分,用拓撲序判斷 最後輸出的時候用單調佇列即可
#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
題目大意: 給定個二元組和一個正整數 要求調出若干個二元組,在滿足的條件下最大化 如果答案為實數x,要求輸出
題解: 0/1分數規劃模板題 用實數二分可能會有精度問題,當然卡的好還是能過去 題解給的做法是我們在的時候由於輸出的要求,我們可以都乘上的係數,然後用揹包直接做
太水了沒寫程式碼