1.三角形。
方法一:组合数:
先假设所有的直线都不平行,则答案为C(n,3)。
当然肯定有平行的直线,我们把所有平行的直线看做一组,将每组平行线的数量统计出来,
如果有一组数量num[i]==2,那么这两个平行线和剩下的所有直线都不能组成三角形,
从总答案中减去C(n-2,1);
若num[i]>2,则除了前面一种情况不合法之外,从这里面选出来的三条也是不合法的。即减去C(num[i],3);
方法二:类似DP的思想:
设数组dp[i][j],表示从前i组直线中选出j条直线的方案数,因为三角形只有3条边,则j只有3个值,1,2,3.在和方法一一样的预处理之后,O(n)dp就可以了。
转移方程:dp[i][3]=dp[i-1][3]+b[i]*dp[i-1][2];
dp[i][2]=dp[i-1][2]+b[i]*dp[i-1][1];
dp[i][1]=dp[i-1][1]+b[i];(根据dp的涵义推出来的。方法和清北1的幸运数有异曲同工之妙。)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=310000;
int read()
{
int res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return res*f;
}
int gcd(int a,int b)
{
if(!b) return a;
else return gcd(b,a%b);
}
struct node
{
int a;
int b;
}l[maxn];
int cmp(node a,node b)
{
if(a.a<b.a) return 1;
if(a.a==b.a&&a.b<b.b) return 1;
return 0;
}
int b[maxn],n,num;
ll dp[maxn][4];
int main()
{
freopen("trokuti.in","r",stdin);
freopen("trokuti.out","w",stdout);
n=read();
for(int x,y,z,g,i=1;i<=n;i++)
{
x=read();y=read();z=read();
if(x==0||y==0) { l[i].a=x;l[i].b=y;}
else {
g=gcd(x,y);
l[i].a=x/g;l[i].b=y/g;}
}
sort(l+1,l+n+1,cmp);
for(int i=1;i<=n;i++)
{
num++;b[num]=1;
while(l[i].a==l[i+1].a&&l[i].b==l[i+1].b&&i<n)
{
b[num]++;
i++;
}
}
dp[1][3]=dp[2][3]=dp[1][2]=0;
dp[1][1]=b[1];dp[2][1]=dp[1][1]+b[2];
dp[2][2]=dp[1][2]+b[2]*dp[1][1];
for(int i=3;i<=num;i++)
{
dp[i][1]=dp[i-1][1]+b[i];
dp[i][2]=dp[i-1][2]+b[i]*dp[i-1][1];
dp[i][3]=dp[i-1][3]+b[i]*dp[i-1][2];
}
cout<<dp[num][3];
fclose(stdin);
fclose(stdout);
return 0;
}
2.列车调度:
暴力模拟一下,发现和单调栈相似,和清北2的T2有相同之处。
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e5+10;
int read()
{
int res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return res*f;
}
int t,n,a[maxn];
int f[maxn];
int main()
{
freopen("manage.in","r",stdin);
freopen("manage.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
t++;f[t]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>f[t])
{
t++;f[t]=a[i];
}
else
{
int l=1,r=t,ans=l;
while(l<=r)
{
int mid=(l+r)/2;
if(f[mid]>a[i])
{
ans=mid;r=mid-1;
}
else l=mid+1;
}
f[ans]=a[i];
}
}
cout<<t;
fclose(stdin);
fclose(stdout);
return 0;
}