本人因為過於懶所以以后就將題解放進原文件中,存入百度網盤,自行下載,里面包含題目網站,源文件,與相應題解(這次沒有寫)
鏈接: https://pan.baidu.com/s/1eSoQ_LFWMxFHPpiXkmy4UA 密碼: cgsk
--------------------------------以后就沒有后邊了-------------------------------------------
活動安排 https://loj.ac/problem/10000
問題描述:設有n個活動的集合E = {1,2,…,n},其中每個活動都要求使用同一資源,如演講會場等,而在同一時間內只有一個活動能使用這一資源。每個活i都有一個要求使用該資源的起始時間si和一個結束時間fi,且si < fi 。如果選擇了活動i,則它在半開時間區間[si, fi)內占用資源。若區間[si, fi)與區間[sj, fj)不相交,則稱活動i與活動j是相容的。也就是說,當si >= fj或sj >= fi時,活動i與活動j相容。選擇出由互相兼容的活動組成的最大集合。
輸入格式
第一行一個整數 n;
接下來的 n行,每行兩個整數 si和 fi。
輸出格式
輸出互相兼容的最大活動個數。
樣例
樣例輸入
4
1 3
4 6
2 5
1 7
樣例輸出
2
數據范圍與提示
1≤n≤1000
其實這種題只要將末尾時間從小到大排序即可,證法請讀者自己思考
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int f,e; }a[1001]; bool cmp(node a,node b) { return a.e<b.e; } int n; int main() { n=read(); for(int i=1;i<=n;i++) a[i].f=read(),a[i].e=read(); sort(a+1,a+n+1,cmp); int ans=1,t=a[1].e; for(int i=2;i<=n;i++) if(a[i].f>=t) ans++,t=a[i].e; cout<<ans; }
種樹 https://loj.ac/problem/10001
題目描述
一條街的一邊有幾座房子。因為環保原因居民想要在路邊種些樹。路邊的地區被分割成塊,並被編號成1..N。每個部分為一個單位尺寸大小並最多可種一棵樹。每個居民想在門前種些樹並指定了三個號碼B,E,T。這三個數表示該居民想在B和E之間最少種T棵樹。當然,B≤E,居民必須記住在指定區不能種多於區域地塊數的樹,所以T≤E-B+l。居民們想種樹的各自區域可以交叉。你的任務是求出能滿足所有要求的最少的樹的數量。
寫一個程序完成以下工作:
輸入輸出格式
輸入格式:
第一行包含數據N,區域的個數(0<N≤30000);
第二行包含H,房子的數目(0<H≤5000);
下面的H行描述居民們的需要:B E T,0<B≤E≤30000,T≤E-B+1。
輸出格式:
輸出文件只有一行寫有樹的數目
輸入輸出樣例
從最后從小到大排序,使用used數組記錄當前位置有沒有樹即可
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int f;int e;int x; }a[50001]; bool used[30001]; bool cmp(node a,node b) { return a.e<b.e; } int n,h; int main() { n=read(),h=read(); for(int i=1;i<=h;i++) a[i].f=read(),a[i].e=read(),a[i].x=read(); sort(a+1,a+h+1,cmp); for(int i=1;i<=h;i++) { int ans=0; for(int j=a[i].e;j>=a[i].f;j--) if(used[j]) ans++; if(ans>=a[i].x) continue; for(int j=a[i].e;j>=a[i].f;j--) { if(!used[j]) used[j]=1,ans++; if(ans==a[i].x) break; } } int sum=0; for(int i=1;i<=n;i++) if(used[i]) sum++; cout<<sum; return 0; } /* 9 4 1 4 2 4 6 2 8 9 2 3 5 2 */
噴水裝置 https://loj.ac/problem/10002
題目描述
長 L米,寬 W 米的草坪里裝有 n 個澆灌噴頭。每個噴頭都裝在草坪中心線上(離兩邊各各 W/2 米)。我們知道每個噴頭的位置(離草坪中心線左端的距離),以及它能覆蓋到的澆灌范圍。
請問:如果要同時澆灌整塊草坪,最少需要打開多少個噴頭?
輸入格式
輸入包含若干組測試數據。
第一行一個整數 T 表示數據組數;
每組數據的第一行是整數 n、L 和 W;
接下來的 n 行,每行包含兩個整數,給出一個噴頭的位置和澆灌半徑(上面的示意圖是樣例輸入第一組數據所描述的情況)。
輸出格式
對每組測試數據輸出一個數字,表示要澆灌整塊草坪所需噴頭數目的最小值。如果所有噴頭都打開也不能澆灌整塊草坪,則輸出 −1 。
樣例
樣例輸入
3
8 20 2
5 3
4 1
1 2
7 2
10 2
13 3
16 2
19 4
3 10 1
3 5
9 3
6 1
3 10 1
5 3
1 1
9 1
樣例輸出
6
2
-1
數據范圍與提示
對於 100% 的數據,n≤15000
這題是線段覆蓋題目,首先先用勾股定理求出線段左右端點的距離,並從當前沒有被覆蓋的t中找到a[i].x<=s並且a[i].y大於當前可以覆蓋的值,並將s=a[i].y,表示使用當前木棍
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline double read() { double f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ double x,y; }a[15001]; bool cmp(node aa,node bb) { if(aa.x!=bb.x)return aa.x<bb.x; return aa.y<bb.y; } double t,l,w; int n; int main() { t=read(); while(t--) { int cnt; n=0; cnt=read(),l=read(),w=read(); for(int i=1;i<=cnt;i++) { double xx=read(),yy=read(); if(yy<=w/2) continue; a[++n].x=xx-sqrt(yy*yy-(w/2)*(w/2)); a[n].y=xx+sqrt(yy*yy-(w/2)*(w/2)); } // cout<<cnt<<" "<<n; // system("pause"); sort(a+1,a+n+1,cmp); // cout<<endl; // for(int i=1;i<=n;i++) cout<<a[i].x<<" "<<a[i].y<<endl; // system("pause"); double t=0,maxn=0; int ans=0; bool f=false; while(t<l) { ans++; for(int i=1;i<=n;i++) { if(a[i].x<=t) { if(a[i].y>=maxn) maxn=a[i].y; } else break; } if(t==maxn&&t<l) { cout<<-1<<endl; f=true; break; } t=maxn; } if(!f) cout<<ans<<endl; } }
加工生產調度 https://loj.ac/problem/10003
題目描述
某工廠收到了n個產品的訂單,這n個產品分別在A、B兩個車間加工,並且必須先在A車間加工后才可以到B車間加工。求怎樣安排這n個產品的加工順序,才能使總的加工時間最短。這里所說的加工時間是指,從開始加工第一個產品到最后所有的產品都已在A、B兩車間加工完畢的時間。
輸入格式
第一行僅—個數據 n,表示產品的數量;
接下來 n 個數據是表示這 n個產品在 A 車間加工各自所要的時間;
最后的 n 個數據是表示這 n 個產品在 B 車間加工各自所要的時間。
輸出格式
第一行一個數據,表示最少的加工時間;
第二行是一種最小加工時間的加工順序。
樣例
樣例輸入
5
3 5 8 7 10
6 2 1 4 9
樣例輸出
34
1 5 4 2 3
數據范圍與提示
對於 100%的數據, 0<n<1000,所有數值皆為整數。
這題就比較神奇,先將m[i]=min(a[i],b[i]) 在從小到大排序(比較嚴格的證明:https://wenku.baidu.com/view/9c31776727d3240c8447ef42.html###),詳細思路見代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } int n,a[1001],b[1001],m[1001],s[1001],ans[1001]; int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) b[i]=read(); for(int i=1;i<=n;i++) m[i]=min(a[i],b[i]),s[i]=i; for(int i=1;i<=n-1;i++) for(int j=i+1;j<=n;j++) if(m[i]>m[j]) swap(m[i],m[j]),swap(s[i],s[j]); // for(int i=1;i<=n;i++) cout<<m[i]<<" "; // cout<<endl; // for(int i=1;i<=n;i++) cout<<s[i]<<" "; // cout<<endl; // system("pause"); int ans1=0,ans2=n+1; for(int i=1;i<=n;i++) { // cout<<m[i]<<" "<<s[i]<<" "<<a[s[i]]<<" "<<b[s[i]]<<" "<<i<<" "; if(m[i]==a[s[i]])ans[++ans1]=s[i]; else if(m[i]==b[s[i]])ans[--ans2]=s[i]; } int s1=0,s2=0; for(int i=1;i<=n;i++) { s1+=a[ans[i]]; if(s1>s2) s2=s1; s2+=b[ans[i]]; } cout<<s2<<endl; for(int i=1;i<n;i++) cout<<ans[i]<<" ";cout<<ans[n]; return 0; }
智力大沖浪 https://loj.ac/problem/10004
題目描述
小偉報名參加中央電視台的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者 m 元。先不要太高興!因為這些錢還不一定都是你的?!接下來主持人宣布了比賽規則:
首先,比賽時間分為 n個時段,它又給出了很多小游戲,每個小游戲都必須在規定期限 ti 前完成。如果一個游戲沒能在規定期限前完成,則要從獎勵費 m 元中扣去一部分錢 wi,wi為自然數,不同的游戲扣去的錢是不一樣的。當然,每個游戲本身都很簡單,保證每個參賽者都能在一個時段內完成,而且都必須從整時段開始。主持人只是想考考每個參賽者如何安排組織自己做游戲的順序。作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!注意:比賽絕對不會讓參賽者賠錢!
輸入格式
輸入共四行。
第一行為 m,表示一開始獎勵給每位參賽者的錢;
第二行為 n,表示有 n 個小游戲;
第三行有 n 個數,分別表示游戲 1 到 n 的規定完成期限;
第四行有 n 個數,分別表示游戲 1 到 n 不能在規定期限前完成的扣款數。
輸出格式
輸出僅一行,表示小偉能贏取最多的錢。
樣例
樣例輸入
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
樣例輸出
9950
數據范圍與提示
對於 100%的數據,有 n≤500,1≤ti≤n。
將罰款從大到小排序,將大的先安排,若不能安排則就拉的越遠越好
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int t; int x; }a[501]; int money,n; bool book[501]; bool cmp(node x1,node x2) { return x1.x>x2.x; } int main() { money=read(),n=read(); for(int i=1;i<=n;i++) a[i].t=read(); for(int i=1;i<=n;i++) a[i].x=read(); sort(a+1,a+n+1,cmp); int ans=0,sum=0; for(int i=1;i<=n;i++) { bool f=false; for(int j=a[i].t;j>=1;j--) if(!book[j]){book[j]=1;f=true;break;} if(!f) { for(int j=n;j>=1;j--) if(!book[j]){book[j]=1;break;} sum+=a[i].x; } } cout<<money-sum; return 0; }
數列極差 https://loj.ac/problem/10005
題目描述
佳佳的老師在黑板上寫了一個由 n 個正整數組成的數列,要求佳佳進行如下操作:每次擦去其中的兩個數 a 和 b,然后在數列中加入一個數 a×b+1,如此下去直至黑板上剩下一個數為止,在所有按這種操作方式最后得到的數中,最大的為 max\maxmax,最小的為 min\minmin, 則該數列的極差定義為 M=max−min。
由於佳佳忙於准備期末考試,現請你幫助他,對於給定的數列,計算出相應的極差 d。
輸入格式
第一行為一個正整數 n 表示正整數序列的長度;
在接下來的 n行中,每行輸入一個正整數。
接下來的一行有一個 0,表示數據結束。
輸出格式
輸出只有一行,為相應的極差 d。
樣例
樣例輸入
3
1
2
3
0
樣例輸出
2
數據范圍與提示
0≤n≤50000。
自己寫了一個證明,
a<b<maxn
a,b,maxn
1)a*b+1 maxn (a*b+1)*maxn+1=a*b*maxn+maxn+1
2)a*maxn+1 b (a*maxn+1)*b+1=a*b*maxn+b+1
3)b*maxn+1 a (b*maxn+1)*a+1=a*b*maxn+a+1
則1)>2)>3)
后可推倒小於情況,
詳情看代碼,用優先隊列維護:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } int n; int x; int main() { priority_queue<int> qmin; priority_queue<int, vector<int>, greater<int> > qmax; n=read(); for(int i=1;i<=n;i++) x=read(),qmin.push(x),qmax.push(x); while(qmin.size()>1) { int a1=qmin.top();qmin.pop(); int a2=qmin.top();qmin.pop(); qmin.push(a1*a2+1); } while(qmax.size()>1) { int a1=qmax.top();qmax.pop(); int a2=qmax.top();qmax.pop(); qmax.push(a1*a2+1); } cout<<qmax.top()-qmin.top(); }
數列分段 https://loj.ac/problem/10006
題目描述
對於給定的一個長度為 N的正整數數列 Ai,現要將其分成連續的若干段,並且每段和不超過 M(可以等於 M),問最少能將其分成多少段使得滿足要求。
輸入格式
第一行包含兩個正整數 N,M,表示了數列 Ai的長度與每段和的最大值;
第二行包含 N 個空格隔開的非負整數 Ai。
輸出格式
輸出文件僅包含一個正整數,輸出最少划分的段數。
樣例
樣例輸入
5 6
4 2 4 5 1
樣例輸出
3
數據范圍與提示
對於 100%的數據,有 N≤10^5,M≤10^9,M 大於所有數的最大值,Ai 之和不超過 10^9。
這種水題不想解釋
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } int n,x,sum,ans=1,m; int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { x=read(); if(sum+x<=m) sum+=x; else ans++,sum=x; //cout<<sum<<" "<<ans<<endl; } cout<<ans; }
線段 https://loj.ac/problem/10007
題目描述
數軸上有 n 條線段,選取其中 k條線段使得這 k 條線段兩兩沒有重合部分,問 k 最大為多少。
輸入格式
第一行為一個正整數 n;
在接下來的 n 行中,每行有 2個數 ai,bi,描述每條線段。
輸出格式
輸出一個整數,為 k 的最大值。
樣例
樣例輸入
3
0 2
2 4
1 3
樣例輸出
2
數據范圍與提示
對於 100%的數據,n≤10^6, 0≤ai<bi≤10^6 。
這道題與活動安排類似
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int x; int y; }a[1000001]; bool cmp(node x1,node x2) { return x1.y<x2.y; } int n; int main() { n=read(); for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(); sort(a+1,a+n+1,cmp); int ans=1,t=a[1].y; for(int i=2;i<=n;i++) if(a[i].x>=t) ans++,t=a[i].y; cout<<ans; }
家庭作業 https://loj.ac/problem/10008
題目描述
老師在開學第一天就把所有作業都布置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為 10,要求在 6天內交,那么要想拿到這 10 學分,就必須在第 6 天結束前交。
每個作業的完成時間都是只有一天。
你的任務就是找到一個完成作業的順序獲得最大學分。
輸入格式
第一行一個整數 N,表示作業的數量;
接下來 N 行,每行包括兩個整數,第一個整數表示作業的完成期限,第二個數表示該作業的學分。
輸出格式
輸出一個整數表示可以獲得的最大學分。保證答案不超過 C/C++
的 int
范圍。
樣例
樣例輸入
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
樣例輸出
15
數據范圍與提示
對於 100% 的數據,N≤10^6,作業的完成期限均小於 7*10^5。
這題與智力大沖浪類似
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int t; int w; }a[1000006]; bool cmp(node x1,node x2) { return x1.w>x2.w; } int n,sum; bool book[1000006]; int f[1000006]; int find(int x) { if(f[x]==x) return x; return f[x]=find(f[x]); } void merge(int x,int y) { f[find(x)]=f[find(y)]; return; } int main() { n=read(); for(int i=1;i<=n;i++) a[i].t=read(),a[i].w=read(); sort(a+1,a+n+1,cmp); for(int i=0;i<=n;i++) f[i]=i; for(int i=1;i<=n;i++) { int ff=find(a[i].t); // cout<<a[i].t<<" "<<ff<<" "<<a[i].w<<" "<<sum<<endl; if(ff!=0) { sum+=a[i].w; merge(ff,ff-1); } } printf("%d",sum); return 0; }
釣魚 https://loj.ac/problem/10009
題目描述
話說發源於小朋友精心設計的游戲被電腦組的童鞋們藐殺之后非常不爽,為了表示安慰和鼓勵,VIP999決定請他吃一次“年年大豐收”,為了表示誠意,他還決定親自去釣魚,但是,因為還要准備2013NOIP,z老師只給了他H(1<=H<=16)個小時的空余時間,假設有N(2<=n<=25)個魚塘都在一條水平路邊,從左邊到右編號為1、2、3、。。。、n)。VIP是個很講究效率的孩子,他希望用這些時間釣到盡量多的魚。他從湖1出發,向右走,有選擇的在一些湖邊停留一定的時間釣魚,最后在某一個湖邊結束釣魚。他測出從第I個湖到I+1個湖需要走5*ti分鍾的路,還測出在第I個湖邊停留,第一個5分鍾可以釣到魚fi,以后再每釣5分鍾魚,魚量減少di。為了簡化問題,他假定沒有其他人釣魚,也不會有其他因素影響他釣到期望數量的魚。請編程求出能釣最多魚的數量。
輸入輸出格式
輸入格式:
第一行:湖的數量n。
第二行:時間h(小時)。
第三行:n個數,f1,f2,…fn。
第四行:n個數,d1,d2,….dn。
第五行:n-1個數,t1,t2,….tn-1
輸出格式:
一個數,所能釣魚的最大數量。
輸入輸出樣例
輸入樣例#1:
2
1
10 1
2 5
2
輸出樣例#1:
31
將時間先算出來,在通過優先隊列進行維護
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } struct node{ int cost; int d; }a[101]; bool operator<( node a, node b ){ return a.cost<b.cost; } priority_queue<node> que; int n,t,h[101],sum,sry,maxn; int main() { n=read();t=read();t*=60; for(int i=1;i<=n;i++) a[i].cost=read(); for(int i=1;i<=n;i++) a[i].d=read(); for(int i=1;i<n;i++) h[i]=read(); // cout<<t;system("pause"); // int sry=0; int tt=t; for(int i=1;i<=n;i++) { sry=0; sum=0; for(int j=1;j<=i;j++) que.push(a[j]); for(int j=1;j<i;j++) sum+=h[j]; // cout<<sum<<endl; t=tt-sum*5; while(t>0) { node s=que.top(); que.pop(); if(s.cost<0) break; sry+=s.cost; // cout<<s.cost<<" "<<t<<endl; s.cost=s.cost-s.d; que.push(s); t-=5; } // cout<<sry<<endl; maxn=max(maxn,sry); while(!que.empty()) que.pop(); } cout<<maxn; return 0; }
糖果傳遞 https://loj.ac/problem/10010
這就有一個比較神奇的證明,不是我寫的,但是非常聰明,
詳情見代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; long long a[1000001],c[1000001]; inline long long read() { long long f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return ans*f; } long long tot,n; int main() { n=read(); for(long long i=1;i<=n;i++) a[i]=read(),tot+=a[i]; tot/=n; for(long long i=1;i<=n;i++) c[i]=c[i-1]+a[i]-tot; sort(c+1,c+n+1); long long bz=c[n/2]; long long sum=0; for(long long i=1;i<=n;i++) sum+=abs(c[i]-bz); cout<<sum; }