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 | 剑刃风暴 |
计算几何,找一个圆与点相切,然后类似扫描线统计一下
浙公网安备 33010602011771号