day2018.10.22模擬賽總結
今天是模擬賽day4了.
T1:
題目大意:給出T個不等式,要求求出每個不等式的解集.其中每個不等式的格式都為,req為中的一個符號.
考場得分:60分.
考場得了60分是因為多寫了一個break,然後就只輸出了兩個區間...
這道題十分容易啊,我們只要看每一個式子的零點存起來並排序,然後統計每一個零點到下一個零點的這段區間是否滿足條件就可以了.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void typedef long long LL; const int N=10000,INF=N+10; int siz,n,opt; int x[N+9],y[N+9],top; int a[N+9],cnt[N+9],b[N+9],t; int ansx[N+9],ansy[N+9],tt; char c[N*10+9]; Abigail into(){ int x; scanf("%s",c); siz=strlen(c); for (int i=0;i<=siz;i++){ if (c[i]<='9'&&c[i]>='0'){ x=c[i-1]=='+'?-1:1; a[++n]=c[i]-'0'; for (;c[i+1]<='9'&&c[i+1]>='0';i++) a[n]=a[n]*10+c[i+1]-'0'; a[n]*=x; } if (c[i]=='<'||c[i]=='>'){ if (c[i+1]=='=') opt=c[i]=='>'?2:3; else opt=c[i]=='>'?0:1; break; } } } Abigail work(){ sort(a+1,a+1+n); int sum=0; a[0]=-N-10; for (int i=1;i<=n;i++) if (a[i]^a[i-1]) b[++t]=a[i],cnt[t]=1; else ++cnt[t]; b[t+1]=N+10;cnt[t+1]=0; b[0]=-N-10;cnt[0]=0; for (int i=0;i<=t;i++){ sum+=cnt[i]; if (opt>1) x[++top]=b[i],y[top]=b[i]; if ((opt==1||opt==3)&&(n-sum&1)) x[++top]=b[i],y[top]=b[i+1]; if ((opt==0||opt==2)&&((n-sum&1)==0)) x[++top]=b[i],y[top]=b[i+1]; } if (opt<2){ tt=top; for (int i=1;i<=top;i++) ansx[i]=x[i],ansy[i]=y[i]; }else for (int i=1;i<=top;i++) if (x[i]==y[i-1]) ansy[tt]=y[i]; else ansx[++tt]=x[i],ansy[tt]=y[i]; } Abigail outo(){ int i,flag=0; for (i=1;i<=tt;i++) if (ansx[i]==-INF){ if (ansy[i]==-INF) continue; printf("(-inf,"); if (ansy[i]==INF) printf("+inf)"); else { printf("%d",ansy[i]); opt<2?putchar(')'):putchar(']'); } flag++; break; }else if (ansy[i]==INF){ if (ansx[i]==INF) break; if (opt<2) printf("(%d,+inf)",ansx[i]); else printf("[%d,+inf)",ansx[i]); flag++; }else{ flag++; opt<2?printf("(%d,%d)",ansx[i],ansy[i]):printf("[%d,%d]",ansx[i],ansy[i]); break; } for (i++;i<=tt;i++) if (ansy[i]==INF){ if (ansx[i]==INF) break; if (opt<2) printf(",(%d,+inf)",ansx[i]); else printf(",[%d,+inf)",ansx[i]); flag++; }else{ flag++; opt<2?printf(",(%d,%d)",ansx[i],ansy[i]):printf(",[%d,%d]",ansx[i],ansy[i]); } if (flag==0) puts("empty"); else puts(""); for (int i=1;i<=siz;i++) c[i]=0; for (int i=1;i<=n;i++) cnt[i]=0; n=0;top=0;t=0;tt=0; } int main(){ freopen("inequality.in","r",stdin); freopen("inequality.out","w",stdout); int T; scanf("%d",&T); while (T--){ into(); work(); outo(); } int _=0; return 0>_<0; }
T2:
題目大意:給定一條鏈的一部分邊,求出第x個點在鏈中的可能位置.
考場得分:100.
直接求出每一條能夠確定的鏈的點的數量,然後跑一個揹包看第x個點所在的鏈在這些鏈中的位置.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void const int N=1000; struct node{ int next,num,flag,rnk; }e[N+9]; int n,x,cnt[N+9],top; bool f[N+9]; bool dfs(int k,int rnk){ bool flag=0; if (k==x) flag=1; e[k].rnk=rnk; if (!e[k].next){ e[k].num=1; return flag; } if (dfs(e[k].next,rnk+1)) flag=1; e[k].num=e[e[k].next].num+1; return flag; } Abigail into(){ int gg; scanf("%d%d",&n,&x); for (int i=1;i<=n;i++){ scanf("%d",&gg); if (gg) e[gg].next=i; else e[i].flag=1; } } Abigail work(){ for (int i=1;i<=n;i++) if (e[i].flag) if (!dfs(i,1)) cnt[++top]=e[i].num; f[0]=1; for (int i=1;i<=top;i++) for (int j=n;j>=cnt[i];j--) f[j]=f[j]||f[j-cnt[i]]; } Abigail outo(){ for (int i=0;i<=n;i++) if (f[i]) printf("%d\n",i+e[x].rnk); } int main(){ freopen("queue.in","r",stdin); freopen("queue.out","w",stdout); into(); work(); outo(); int _=0; return 0>_<0; }
T3:
題目大意:給定n個籃子,每個籃子裡有三樣物品ai,bi,ci.將這些籃子分為三份,求第一份的價值最大的A物品的價值+第二份價值最大的B物品的價值+第三份價值最大的C物品的價值最小是多少.
考場得分:50.
一開始想到了一個偽正解是二分套二分,寫完了兩個二分之後就把這個做法的正確性給推翻了.
然後想著拿暴力分,直接把兩個二分換成了暴力列舉就有了50分.具體就是列舉A物品和B物品的最大值,然後就把C物品最小的最大值求出,就可以做到列舉.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void typedef long long LL; const int N=100000; const LL INF=(1LL<<50LL)-1LL; int n; LL a[N+9],b[N+9],c[N+9],ans; LL check(LL x,LL y){ LL C=0LL; for (int i=1;i<=n;i++) if (a[i]>x&&b[i]>y) C=max(C,c[i]); return C; } Abigail into(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lld%lld%lld",&a[i],&b[i],&c[i]); } Abigail work(){ ans=INF; for (int i1=0;i1<=n;i1++) for (int i2=0;i2<=n;i2++) ans=min(ans,check(a[i1],b[i2])+a[i1]+b[i2]); } Abigail outo(){ printf("%lld\n",ans); } int main(){ freopen("basket.in","r",stdin); freopen("basket.out","w",stdout); int T; scanf("%d",&T); while (T--){ into(); work(); outo(); } return 0; }
我們考慮簡化問題,當只有兩種物品的時候怎麼做.
只有兩種物品時,考慮按照a物品的價值給籃子從大到小排序,那麼b物品的最大值就會越來越大.考慮維護這個最大值,用一個堆,當ai變小時,將所有新出現的未被覆蓋的籃子給加入到堆裡,這樣就可以做到解決這個簡化後的問題.
考慮拓展到三種物品的情況,我們依然列舉a,然後考慮將每一個未被覆蓋的籃子以(b,c)為座標畫到一個座標系中.這樣我們就會得到一張圖,在這張圖中,我們以b為橫座標,c為縱座標.
然後就會有一張類似於下圖的圖:
我們在這張圖中要找到b+c最小的能夠覆蓋全部點的值,其實就是在類似於上圖的的階梯形線條的淡藍色的點的橫縱座標相加的最小值.
那麼考慮使用一個set來維護這些資訊即可.
那麼程式碼如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1;
int n;
struct basket{
int a,b,c;
}gg[N+9];
struct point{
int x,y;
point(int xx,int yy){x=xx;y=yy;}
bool operator < (const point &p)const{return x<p.x||x==p.x&&y<p.y;}
};
set<point> m;
multiset<int> v;
LL ans;
bool cmp(basket a,basket b){return a.a>b.a;}
Abigail into(){
m.clear();v.clear();
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d%d",&gg[i].a,&gg[i].b,&gg[i].c);
gg[n+1].a=gg[n+1].b=gg[n+1].c=0;
}
Abigail work(){
sort(gg+1,gg+1+n,cmp);
ans=LL(gg[1].a);
m.insert(point(INF,0));m.insert(point(0,INF));
v.insert(0);
for (int i=1;i<=n;i++){
point p(gg[i].b,gg[i].c);
if (m.count(p)) continue;
m.insert(p);
#define pi set<point>::iterator
pi next=m.find(p),last=next++,it=last--;
if ((*it).y<=(*next).y) m.erase(it);
else{
v.insert((*it).x+(*next).y);
v.insert((*last).x+(*it).y);
v.erase(v.find((*last).x+(*next).y));
while ((*it).y>=(*last).y){
--last;--it;--next;
v.erase(v.find((*last).x+(*it).y));
v.erase(v.find((*it).x+(*next).y));
v.insert((*last).x+(*next).y);
m.erase(it);
it=m.find(p);
last=it,--last;
next=it,++next;
}
}
#undef pi
ans=min(ans,LL(gg[i+1].a)+LL(*v.begin()));
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
freopen("basket.in","r",stdin);
freopen("basket.out","w",stdout);
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}