套题 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;
}
50分

 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;
}
100分

 

posted @ 2017-08-21 11:35  浪矢-CL  阅读(198)  评论(0编辑  收藏  举报