联赛前(伪)数据结构专题总结
?[Scoi2010]游戲
時間限制:?1 Sec??內存限制:?128 MB
Description
lxhgww最近迷上了一款游戲,在游戲里,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。并且每種裝備最多只能使用一次。 游戲進行到最后,lxhgww遇到了終極boss,這個終極boss很奇怪,攻擊他的裝備所使用的屬性值必須從1開始連續遞增地攻擊,才能對boss產生傷害。也就是說一開始的時候,lxhgww只能使用某個屬性值為1的裝備攻擊boss,然后只能使用某個屬性值為2的裝備攻擊boss,然后只能使用某個屬性值為3的裝備攻擊boss……以此類推。 現在lxhgww想知道他最多能連續攻擊boss多少次?Input
輸入的第一行是一個整數N,表示lxhgww擁有N種裝備 接下來N行,是對這N種裝備的描述,每行2個數字,表示第i種裝備的2個屬性值Output
輸出一行,包括1個數字,表示lxhgww最多能連續攻擊的次數。Sample Input
31 2
3 2
4 5
Sample Output
2HINT
【數據范圍】
對于30%的數據,保證N < =1000
對于100%的數據,保證N < =1000000
?
題解
? ? ? 在yzh大佬提醒下發現這題幾乎和好幾個月以前做過的一道二分圖題意完全一樣,但是二分圖的復雜度是O(nm)的,這題理論上講絕對過不了,但是用了十分神奇的卡常方法之后卻真的能過。
? ? ? ?正解是并查集,把每個裝備看作一條邊,把屬性看成點。一個環里面一定都能滿足,一棵樹里只有一個點不滿足。用并查集維護點的連通性,如果一個聯通塊里有點數-1條邊就讓最大的不滿足,通過標記集合來確定有多少點是可行的。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int sj=1000010; const int sj1=10005; int n,h[sj+sj1],e,jg,l[sj+sj1],a1,a2,f[sj+sj1],id; struct B {int ne,v; }b[sj<<1]; void add(int x,int y) {b[e].ne=h[x],b[e].v=y,h[x]=e++; } bool find(int x) {for(int i=h[x];i!=-1;i=b[i].ne){e=b[i].v;if(f[e]!=id){f[e]=id;if(l[e]==-1||find(l[e])){l[e]=x;return 1;}}}return 0; } int main() {scanf("%d",&n);memset(h,-1,sizeof(h));memset(l,-1,sizeof(l));for(int i=1;i<=n;i++){scanf("%d%d",&a1,&a2);add(a1,sj1+i),add(a2,sj1+i);}for(int i=1;i<=sj1;i++){id=i;if(find(i)) jg++;else break;}printf("%d",jg);return 0; } game #include<iostream> #include<cstring> #include<cstdio> using namespace std; const int sj=10005; int n,a1,a2,f[sj]; bool v[sj]; int find(int x) {if(f[x]==-1) return x;f[x]=find(f[x]);return f[x]; } void hb(int x,int y) {if(x>y) swap(x,y);f[x]=y;if(!v[x]) v[x]=1;else v[y]=1; } int main() {scanf("%d",&n);memset(f,-1,sizeof(f));for(int i=1;i<=n;i++){scanf("%d%d",&a1,&a2);a1=find(a1),a2=find(a2);if(a1==a2) v[a1]=1;else hb(a1,a2);} for(int i=1;i<=sj;i++)if(!v[i]){printf("%d",i-1);break;}return 0; } game2?
?
JC loves Mkk
?時間限制:?1 Sec??內存限制:?64 MB
輸入
第1行,包含三個整數。n,L,R。
第2行n個數,代表a[1..n]。
輸出
僅1行,表示詢問答案。
如果答案是整數,就輸出整數;否則,輸出既約分數“P/Q”來表示。
樣例輸入
5 3 4 3 1 2 4 5樣例輸出
7/2HINT 1≤L≤R≤n≤10^5,0≤ai≤10^9,保證問題有解,數據隨機生成題解
神奇的二分……我明知道平均值問題我只會二分,但是看到輸出精確結果還是很不敢想,初次之外又一籌莫展。確實是需要實數二分,精度問題需要long double。把每一個a[i]都減去mid,那么問題就在于找到一個滿足條件的區間,使區間和大于0。區間和轉化為前綴和是司空見慣的,環拆成鏈也是自然。怎樣確保選偶數個呢?維護一個單調隊列,在奇數中和偶數中各找遞增的前綴和。i和r作為維護單調隊列的標準,每次檢查是否有遞增的前綴和,即滿足條件的區間和,這兩個前綴和之間的差就是我們需要的答案的分母。分子/分母=二分結果,通過分母×二分結果向上取整得到整數形式的分子。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int sj=200010; const long double eps=1e-6; int n,l,r,q[2][sj],h[2],t[2]; long long fz,fm,a[sj],gc; long double mid,zj,yj,sum[sj]; bool op; bool check(long double x) {for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]-x;h[1]=h[0]=t[1]=t[0]=1;for(int i=l;i<=n;i++){int j=i-l,op=i&1;while(h[op]<t[op]&&sum[j]-sum[q[op][t[op]-1]]<0) t[op]--;q[op][t[op]++]=j;if(q[op][h[op]]<i-r) h[op]++;if(sum[i]-sum[q[op][h[op]]]>0) {fm=i-q[op][h[op]];return 1;}}return 0; } long long gcd(long long x,long long y) {if(y==0) return x;return gcd(y,x%y); } int main() {scanf("%d%d%d",&n,&l,&r);for(int i=1;i<=n;i++){ scanf("%lld",&a[i]);if(a[i]>yj) yj=a[i];}for(int i=1;i<n;i++) a[i+n]=a[i];l+=l&1,r-=r&1,n<<=1;while(zj<yj-eps){mid=(zj+yj)/2;if(check(mid)) zj=mid;else yj=mid;}mid=(zj+yj)/2;fz=(long long)(mid*fm+0.5);gc=gcd(fz,fm);fz/=gc,fm/=gc;printf("%lld",fz);if(fm!=1) printf("/%lld",fm);return 0; } candy
?
[Usaco2013 Open]Photo
時間限制:?1 Sec??內存限制:?128 MB
題目描述
Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered from 1..N. Accordingly, he snapped M (1 <= M <= 100,000) photos, each covering a contiguous range of cows: photo i contains cows a_i through b_i inclusive. The photos collectively may not necessarily cover every single cow. After taking his photos, FJ notices a very interesting phenomenon: each photo he took contains exactly one cow with spots! FJ was aware that he had some number of spotted cows in his herd, but he had never actually counted them. Based on his photos, please determine the maximum possible number of spotted cows that could exist in his herd. Output -1 if there is no possible assignment of spots to cows consistent with FJ"s photographic results.?
給你一個n長度的數軸和m個區間,每個區間里有且僅有一個點,問能有多少個點
輸入
?* Line 1: Two integers N and M.
* Lines 2..M+1: Line i+1 contains a_i and b_i.
輸出
* Line 1: The maximum possible number of spotted cows on FJ"s farm, or -1 if there is no possible solution.
樣例輸入
5 3 1 4 2 5 3 4INPUT DETAILS: There are 5 cows and 3 photos. The first photo contains cows 1 through 4, etc.樣例輸出
1OUTPUT DETAILS: From the last photo, we know that either cow 3 or cow 4 must be spotted. By choosing either of these, we satisfy the first two photos as well.題解
久違的單調隊列優化dp!題目敘述有點像小暑假考試的《守衛》,但是那題我至今沒有改出來,而且《守衛》凡是沒有看到的地方都可能有,和這題有所區別。還是就題論題吧,每一個區間里必須有點,所以從某一點向前最遠到不包括它的一個區間左端點至少要有一個點,這是可行解的左端點;每個區間里只有一個,所以從包含它的區間左端點再向左才有點,這是可行解的右端點。左端點取max,右端點取min,我們就得到了可行的轉移區域。對于每個點來說可行區域是單調向右滑動的,可以用單調隊列優化。對于每個點,我們把隊列更新到r[i],再把l[i]之前的刪除出隊列,就可以取隊首轉移了。f[i]=max{f[j],l[i]<=j<=r[i]}+1
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int sj=200010; int n,m,f[sj],q[sj],h,t,l[sj],r[sj],a1,a2,ans,te; void getlr() {for(int i=1;i<=n+1;i++) r[i]=i-1;for(int i=1;i<=m;i++) {scanf("%d%d",&a1,&a2);if(a1>l[a2+1]) l[a2+1]=a1;if(a1-1<r[a2]) r[a2]=a1-1;}for(int i=2;i<=n+1;i++) l[i]=max(l[i-1],l[i]);for(int i=n;i>=1;i--) r[i]=min(r[i+1],r[i]); } int main() { scanf("%d%d",&n,&m);getlr();h=t=te=1,q[1]=0;for(int i=1;i<=n+1;i++){while(te<=r[i]){if(f[te]==-1){te++;continue;}while(h<=t&&f[q[t]]<f[te]) t--;q[++t]=te;te++; }while(h<=t&&q[h]<l[i]) h++;if(h<=t) {f[i]=f[q[h]]+1;if(i==n+1) f[i]--;}else f[i]=-1;}printf("%d",f[n+1]);return 0; } photo
轉載于:https://www.cnblogs.com/moyiii-/p/7588568.html
總結
以上是生活随笔為你收集整理的联赛前(伪)数据结构专题总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windbg脚本和扩展工具开篇
- 下一篇: 【济宁百瑞达机械设备有限公司——文化拓展