hihocoder [Offer收割]编程练习赛14

A 小Hi和小Ho的礼物
post by http://www.cnblogs.com/bitch1319453/

在一个有重复数字的数组中选择4个位置互不同的数,使得存在p+q==i+j

乍一看可以先排序,先选择两个数,然后o(N)解决2sum问题,整体复杂度n*n*n,不满足要求。

这个时候你需要换个思路,容斥一下

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
const int maxm=2000008;
const int maxn=1008;
int sum[maxm];
int cnt[maxm];
int main()
{
	int n;
	int a[maxn];
	while(scanf("%d",&n)==1)
	{
		memset(cnt,0,sizeof(cnt));
		memset(sum,0,sizeof(sum));
		set<int> st;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			cnt[a[i]]++;
			for(int j=1;j<i;j++)
				sum[a[i]+a[j]]++;
			st.insert(a[i]);
		}
		long long ans=0;
		for(int i=0;i<maxm;i++)
		{
			long long x=sum[i];
			ans+=(x-1)*x/2;
		}
		for(int i=1;i<=n;i++)
		{
			for(set<int>::iterator it=st.begin();it!=st.end();it++)
			{
				int x=*it;
				long long y=cnt[x];
				if(x!=a[i])
				{
					ans-=y*(y-1)/2;
				}
				else
					ans-=(y-1)*(y-2)/2;
			}
		}
		printf("%lld\n",ans*2);
	}
	return 0;
}

 

B 投掷硬币

非常裸的概率dp,定义dp[i][j]为投掷i次正面朝上次数为j的概率,那么dp[i][j]=dp[i-1][j-1]*w[i]+dp[i-1][j]*(1-w[i])

 

C 可疑的记录

由于只添加了一条边,我们容易知道:

定义祖先的概念:1.它的父亲节点是它的祖先2.它父亲的祖先是它的祖先

那么若有一条边指向了它的父亲,则这条边是可疑的。如果找到了这样的边,则可疑的一定是这条边

若树上有一个点的入度大于1,那么所有指向它的边都是可疑的

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100008;
struct fuck{
	int u,v,id,next;
}edge[maxn<<1];
int tol;
int head[maxn];
int du[maxn];
void init()
{
	tol=0;
	memset(head,-1,sizeof(head));
	memset(du,0,sizeof(du));
}
void addedge(int u,int v,int id)
{
	edge[tol].u=u;
	edge[tol].v=v;
	edge[tol].id=id;
	edge[tol].next=head[u];
	head[u]=tol++;
}
bool  vis[maxn],onvis[maxn];
int ans[maxn],idx;
void dfs(int u)
{
	vis[u]=onvis[u]=true;
	int i;
	for(i=head[u];i!=-1;i=edge[i].next)
	{
		int v=edge[i].v;
		if(!vis[v])
		{
			dfs(v);
			onvis[v]=false;
		}
		if(onvis[v])
			ans[idx++]=edge[i].id;
	}
}
int main()
{
	int n,i,j,u,v;
	while(scanf("%d",&n)==1)
	{
		init();
		vector<vector<int> > p(n+1);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&u,&v);
			addedge(u,v,i);
			du[v]++;
			p[v].push_back(i);
		}
		memset(vis,false,sizeof(vis));
		memset(onvis,false,sizeof(onvis));
		idx=0;
		dfs(1);
		if(idx>0)
		{
			printf("%d\n",ans[idx-1]);
		}
		else
		{
			for(u=1;u<=n;u++)
				if(du[u]>1)
				{
					int len=p[u].size();
					for(i=0;i<len;i++)
					{
						if(i!=0)
							printf(" ");
						printf("%d",p[u][i]);
					}
					printf("\n");
					break;
				}
		}
	}
	return 0;
 } 

  

D 剑刃风暴

计算几何,找一个圆与点相切,然后类似扫描线统计一下

 

posted on 2017-04-17 22:38  此剑之势愈斩愈烈  阅读(180)  评论(0编辑  收藏  举报

导航