1.BOJ 320
求一个数组的有多少组任意三个数能够组成三角形
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,in[3100];
int sea(int l,int h,int num){
int ans=l-1;
while(l<=h){
int mid=(l+h)>>1;
if(in[mid]>=num)
h=mid-1;
else{
l=mid+1;
ans=mid;
}
}
return ans;
}
int main(){
int i,j,t,T;
long long ans;
scanf("%d",&T);
for(t=1;t<=T;t++){
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&in[i]);
sort(in+1,in+n+1);
ans=0;
for(i=1;i<=n;i++)
for(j=i+1;j<n;j++){
ans+=sea(j+1,n,in[i]+in[j])-j;
}
printf("%lld\n",ans);
}
}
2.POJ 2967
这题巨坑,得加读入优化才能过==
先O(n)扫描出最小的两个和最大的一个,判断是否全都可以;
否则,如果全部不可以的话,可以证明其最“密”的形式即为fibonacci数列,所以当n>m(Fm>2 000 000 000)时必有解。否则再排序。
根据题目的数据范围当n>50时必有解
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1000005;
int n, a[MAXN];
int readInteger()
{
int res = 0;
char ch = getchar();
while(ch >= '0' && ch <= '9')
{
res = res * 10 + ch - '0';
ch = getchar();
}
return res;
}
bool judge(int a, int b, int c)
{
return a > c - b;
}
bool judge()
{
if(n <= 3)
{
return false;
}
if(judge(a[0], a[1], a[n-1]))
{
return false;
}
if(n>50) return 1;
for(int i=2;i<n;++i)
{
if(judge(a[i-2], a[i-1], a[i]))
{
return true;
}
}
return false;
}
int main()
{
n = readInteger();
for(int i=0;i<n;++i)
a[i] = readInteger();
sort(a, a + n);
if(judge())
printf("The set is accepted.\n");
else
printf("The set is rejected.\n");
return 0;
}
2013编程之美资格赛第三题 http://programming2013.cstnet.cn/qualification/problem/3
LCA+sort判断
下面代码参考别人的
LCA用tarjan去求
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=100000+5;
struct Node {
int beg, fa,pre, h;
vector<int>query;
} a[N];
struct Edge {
int next, len, t;
} e[N<<1];
struct Query {
int x, y, ans;
} q[N];
int n, M, m;
bool vis[N];
int fa[N];
int find(int u) {
int v=fa[u];
while (v!=fa[v])v=fa[v];
return fa[u]=v;
}
int init(int n) {
M=1;
for (int i=1; i<=n; i++) {
//开始边
a[i].beg=0;
//父亲编号
a[i].fa=i;
//深度
a[i].h=0;
//相关查询
a[i].query.clear();
//是否在tarjan中处理过
vis[i]=false;
//tarjan并查集
fa[i]=i;
}
}
//添加一个条有向边
void add(int u, int v, int w) {
e[++M].t=v;
e[M].len=w;
e[M].next=a[u].beg;
a[u].beg=M;
}
//开始建树
int build(int u) {
//枚举相连的点
for (int cur=a[u].beg, v; v=e[cur].t, cur; cur=e[cur].next)
//非父亲节点
if (v!=a[u].fa) {
//设置为父亲节点
a[v].fa=u;
//与父亲节点的距离
a[v].pre=e[cur].len;
//深度+1
a[v].h=a[u].h+1;
//递归建树
build(v);
}
}
//tarjan求树上两点公共祖先
int solve(int u) {
//已访问
vis[u]=true;
//自成集合
fa[u]=u;
//枚举该点相关的查询
for (int i=0;i<a[u].query.size();i++){
//另一个点
int v=q[a[u].query[i]].x+q[a[u].query[i]].y-u;
//如果已经访问过
if (vis[v]){
//得出两点的最近公共祖先
q[a[u].query[i]].ans=find(v);
}
}
//枚举子节点
for (int cur=a[u].beg,v;v=e[cur].t,cur;cur=e[cur].next)
if(v!=a[u].fa && !vis[v]){
solve(v);
//合并集合
fa[v]=u;
}
}
//回答问题
void answer(int i) {
int x=q[i].x,y=q[i].y,z=q[i].ans;
if(z<0){
printf("No\n");
return ;
}
//相隔超过50个边,一定满足要求
if (a[x].h+a[y].h-2*a[z].h>=50){
printf("Yes\n");
return ;
}
//记录所有路程边
vector<int>b;
//x点到最近公共祖先z的路径
while (x!=z){
b.push_back(a[x].pre);
x=a[x].fa;
}
//y点到最近公共祖先z的路径
while (y!=z){
b.push_back(a[y].pre);
y=a[y].fa;
}
//排序
sort(b.begin(),b.end());
//判定是否有可构成三角形的
for (int i=2;i<b.size();i++)
if (b[i-2]+b[i-1]>b[i]){
printf("Yes\n");
return;
}
//没有符合要求的边
printf("No\n");
return ;
}
//展示节点记录a中的数据
void display_a(int i){
printf("ID=%d,fa=%d,pre=%d,h=%d\n",i,a[i].fa,a[i].pre,a[i].h);
for (int j=0;j<a[i].query.size();j++)
printf("%d ",a[i].query[j]);
printf("\n");
}
//展示查询记录q中的数据
void display_q(int i){
printf("ID=%d,x=%d,y=%d,z=%d\n",i,q[i].x,q[i].y,q[i].ans);
}
int main() {
int total, tt=0;
//读入Case数
cin>>total;
while (total--) {
//读入点数
scanf("%d", &n);
//初始化各个数组
init(n);
int u, v, w;
//读入树上边数
for (int i=1; i<n; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
scanf("%d", &m);
//读入查询
for (int i=0; i<m; i++) {
scanf("%d%d", &u, &v);
q[i].x=u, q[i].y=v;
q[i].ans=-1;
//把查询编号记录在关联的点上
a[u].query.push_back(i);
a[v].query.push_back(i);
}
//以1为根节点建图
build(1);
//开始tarjan求查询点最近公共祖先
solve(1);
printf("Case #%d:\n", ++tt);
//for (int i=1;i<=n;i++)display_a(i);
//for (int i=0;i<m;i++)display_q(i);
for (int i=0; i<m; i++) {
//回答每个查询
answer(i);
}
}
return 0;
}
LCA用定义求法
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
struct edge{
int v, len;
edge(int _v, int _len):v(_v), len(_len){}
};
int T, N, M;
vector<edge> e[100005];
int p[100005], depth[100005], len[100005];
void dfs(int u, int f, int d, int l){
p[u] = f, depth[u] = d, len[u] = l;
for(int i = 0; i < e[u].size(); ++i){
int v = e[u][i].v;
if(v == f) continue;
dfs(v, u, d + 1, e[u][i].len);
}
}
int s[50];
bool query(int u, int v){
int cnt = 0;
while(u != v){
if(depth[u] > depth[v]){
s[cnt++] = len[u];
u = p[u];
}else if(depth[u] < depth[v]){
s[cnt++] = len[v];
v = p[v];
}else{
s[cnt++] = len[u];
s[cnt++] = len[v];
u = p[u];
v = p[v];
}
if(cnt > 46) return true;
}
sort(s, s + cnt);
for(int i = 2; i < cnt; ++i){
if(s[i-2] + s[i-1] <= s[i]) continue;
return true;
}
return false;
}
void solve(){
scanf("%d", &N);
for(int i = 1; i <= N; ++i) e[i].clear();
for(int i = 1; i < N; ++i){
int u, v, len;
scanf("%d%d%d", &u, &v, &len);
e[u].push_back(edge(v, len));
e[v].push_back(edge(u, len));
}
dfs(1, 0, 0, 0);
scanf("%d", &M);
for(int i = 0; i < M; ++i){
int u, v; scanf("%d%d", &u, &v);
printf(query(u, v) ? "Yes\n" : "No\n");
}
}
int main(int argc, char** argv) {
scanf("%d", &T);
int nCase = 1;
while(nCase <= T){
printf("Case #%d:\n", nCase++);
solve();
}
return 0;
}