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 ",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 ",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(" "); break; } } } return 0; }
D | 剑刃风暴 |
计算几何,找一个圆与点相切,然后类似扫描线统计一下