套题 8.21
. 1. 三角形
(trokuti.cpp/c/pas)
【 问题描述 】
平面上有N条直线,用方程A i x + B i y +C i =0表示。这些直线没有三线共点的。
现在要你计算出用这些直线可以构造出多少三角形?
【输入格式】 】
第1行:一个整数N(1 ≤ N≤ 300000)。
下面N行:每行3个整数:Ai, Bi 和Ci,表示对应直线方程的系数。不超过10^9.
输出格式】 】
一行,一个整数。
input 1
6
0 1 0
-5 3 0
-5 -2 25
0 1 -3
0 1 -2
-4 -5 29
input 2
5
-5 3 0
-5 -3 -30
0 1 0
3 7 35
1 -2 -1
output 1
10
output 2
10
【 数据规模与约定】 】
40%的数据,N ≤1000;
对于100%的数据,N≤300000。
太可恶了!!第四十行忘处理了,只得了10分。
(也就是,最后一组斜率忘记加到数组中了)
2 #include<queue> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<queue> 7 #include<math.h> 8 using namespace std; 9 #define LL long long 10 LL n; 11 double q[300009]; 12 int sum[300009],cnt; 13 LL all; 14 LL C(LL m,LL n) 15 { 16 if(n==2) return (m-1)*m/2; 17 if(n==3) return m*(m-1)*(m-2)/6; 18 } 19 int main() 20 { 21 freopen("trokuti.in","r",stdin); 22 freopen("trokuti.out","w",stdout); 23 scanf("%lld",&n); 24 25 double a,b,c; 26 for(int i=1;i<=n;i++) 27 { 28 scanf("%lf%lf%lf",&a,&b,&c); 29 q[i]=a / b; 30 } 31 32 sort(q+1,q+1+n); 33 34 35 LL tot=1; 36 for(int i=2;i<=n;i++) 37 if(q[i]==q[i-1]) 38 ++tot; 39 else sum[++cnt]=tot,tot=1; 40 sum[++cnt]=tot; 41 all=C(n,3); 42 for(int i=1;i<=cnt;i++) 43 { 44 if(sum[i]>=2) all-=(n-sum[i])*C(sum[i],2); 45 if(sum[i]>=3) all-=C(sum[i],3); 46 } 47 cout<<all; 48 return 0; 49 }
另一种做法。
#include<iostream> #include<queue > #include<algorithm> #include<cstdio> using namespace std; double k[300009]; int n,sum[300009],tot,cnt; int f[300009];double a,b,c; long long ans; int main() { freopen("trokuti.in","r",stdin); freopen("trokuti.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&a,&b,&c); k[i]=a/b; } sort(k+1,k+1+n); cnt=0; for(int i=1;i<=n+1;i++) { if(k[i]!=k[i-1]) sum[cnt++]=tot,tot=1; else tot++; } for(int i=1;i<=cnt;i++) f[i]=f[i-1]+sum[i]; for(int i=1;i<cnt;i++) ans+=(long long )(1LL*sum[i]*f[i-1]*(f[cnt]-f[i])); cout<<ans; return 0; }
2. 列车调度
(manage.cpp/c/pas)
【 问题描述 】
有N辆列车,标记为1,2,3,…,N。它们按照一定的次序进站,站台共有K个轨道,轨道遵从 先进先出的原则。列车进入站台内的轨
道后可以等待任意时间后出站,且所有列车不可后退。现在要使出站的顺序变为N,N-1,N-2,…,1,询问K的最小值是多少。
【输入格式】 】
文件名为manage.in。
输入共2行。
1 1个正整数N,表示N辆列车。
第 2 行包含N个正整数,为1至N的一个排列,
表示进站次序。
【输出格式】 】
文件名为manage.out。
输出共1行,包含1个整数,表示站台内轨
道数K的最小值。
【输入输出样例2 2】 】
manage.in manage.out
9
1 3 2 4 8 6 9 5 7
5
最长上升子序列
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> #include<math.h> using namespace std; int maxn,n,a[100009],B[100009],cnt; int find(int x) { int l,r,mid; l=0,r=cnt; while(l<=r) { mid=(l+r)/2; if(B[mid]>=x) r=mid-1; else l=mid+1; } return l; } int main() { freopen("manage.in","r",stdin); freopen("manage.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); B[0]=-1;cnt=0; for(int i=1;i<=n;i++) { if(a[i]>B[cnt]) B[++cnt]=a[i]; else{ int t=find(a[i]); B[t]=a[i]; } } cout<<cnt; return 0; }
3. 保留道路
(road.cpp/c/pas)
【 问题描述 】
很久很久以前有一个国家,这个国家有N个城市,
城市由1,2,3,…,N标号,城市间有M条双向道路,每
条道路都有两个属性g和s,两个城市间可能有多条
道路,并且可能存在将某一城市与其自身连接起来
的道路。后来由于战争的原因,国王不得不下令减
小花费从而关闭一些道路,但是必须要保证任意两
个城市相互可达。
道路花费的计算公式为wG*max{所有剩下道路的属
性g}+wS*max{所有剩下道路的属性s},其中wG和
wS是给定的值。国王想要在满足连通性的前提下使
这个花费最小,现在需要你计算出这个花费。
【输入格式】 】
输入文件名为road.in。
第一N和M。
第二行包含两个正整数wG和wS。
后面的M行每行描述一条道路,包含四个正
整数u,v,g,s,分别表示道路连接的两个城市
以及道路的两个属性。
【 【输出格式】 】
输出文件名为road.out。
输出一个整数,表示最小花费。若无论如
何不能满足连通性,输出-1。
【 【输入输出样例】 】
road.in road.out
3 3
2 1
10 15
2 4 20
1 3 5 1
30
【 数据规模与约定】 】
1,M≤20;
311 50%的数据,N≤200,M≤50;
对于100%的数据,N≤400,M≤50000,
wG,wS,g,s≤1000000000。
50分思路: 比较简单的做法。
(1)先从小到大枚举maxg
(2)对于每一个maxg,选出所有满足g<=maxg的边,按照s从小到大排序,克鲁斯卡尔建最小生成树。得到maxs, 总答案和ans取max。
复杂度大概是m*m

#include<iostream> #include<queue> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<math.h> using namespace std; struct node{ int u,v; int g,s; }a[50009],b[50009]; int n,m,Wg,Ws; int G[50009],f[500]; long long INF=1LL << 62,ans=1LL << 62; bool vis[500]; bool cmp(node x,node y) { return x.s<y.s; } int find(int x) { while(x!=f[x]) x=f[x]=f[f[x]]; return x; } void bing(int x,int y) { int f1=find(x),f2=find(y); f[f1]=f2; } int main() { freopen("road.in","r",stdin); freopen("road.out","w",stdout); scanf("%d%d",&n,&m); scanf("%d%d",&Wg,&Ws); for(int i=1,u,v,g,s;i<=m;i++) { scanf("%d%d%d%d",&u,&v,&g,&s) ; a[i].u=u,a[i].v=v,a[i].g=g,a[i].s=s; G[i]=g; } sort(G+1,G+1+m); sort(a+1,a+1+m,cmp); for(int k=1;k<=m;k++) { int maxG=G[k],cnt=0,maxS,tot=n; for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i <= m;i++) if(a[i].g <= maxG ) b[++cnt]=a[i]; for(int i=1;i<=cnt;i++) { int f1,f2; f1=find(b[i].u),f2=find(b[i].v); if(f1!=f2) { bing(f1,f2),tot--; maxS=b[i].s; } if(Wg*1LL*maxG+1LL*Ws*maxS > ans) continue; if(tot==1) { ans=min(ans,1LL*Wg*maxG+1LL*Ws*maxS); break; } } } if(ans==INF ) cout<<-1; else cout<<ans; return 0; }
100分思路:
上一个做法时,每枚举一个maxg都要建一次树,选边的时候要把所有的边都要扫一遍,而造成了很多重复的地方
,那些就想办法,把选边的复杂度降低。
(1)以g为第一关键字,s为第二关键字排序。(很奇妙)
(2)再建树的时候维护一个数组表示,当前为止最优答案的边集(集合按照s排序)。每枚举一个g增加了一条边,把这条边插到集合中。
(3)再去建树,如果能建成树更新答案。

#include<iostream> #include<queue> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<math.h> using namespace std; typedef long long LL; struct node{ int u,v; LL g,s; }a[50009],b[50009]; int n,m,Wg,Ws; int G[50009],f[500],to[50009]; long long INF=1LL << 62,ans=1LL << 62; bool cmp(node x,node y) { if(x.g==y.g) return x.s<y.s; else return x.g<y.g; } int find(int x) { while(x!=f[x]) x=f[x]=f[f[x]]; return x; } int main() { freopen("road.in","r",stdin); freopen("road.out","w",stdout); scanf("%d%d",&n,&m); scanf("%d%d",&Wg,&Ws); for(int i=1,u,v,g,s;i<=m;i++) { scanf("%d%d%d%d",&u,&v,&g,&s) ; a[i].u=u,a[i].v=v,a[i].g=g,a[i].s=s; } sort(a+1,a+1+m,cmp); int tot=0,cnt; for(int k=1;k<=m;k++) { if(a[k].s*Ws+a[k].g*Wg > ans) continue; for(int i=1;i<=n;i++) f[i]=i; int i; for( i=tot;i>=1;i--) if(a[to[i]].s>a[k].s) to[i+1]=to[i]; else break; tot++,to[i+1]=k; cnt=0; for( i=1;i<=tot;i++) { int f1,f2; f1=find(a[to[i]].u),f2=find(a[to[i]].v); if(f1!=f2) { f[f1]=f2; to[++cnt]=to[i]; } } if(cnt==n-1) ans=min(ans,a[k].g*Wg+a[to[cnt]].s*Ws); tot=cnt; } if(ans==INF ) cout<<-1; else cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App