题意:有n个球,从盒子中挑两个球出来。先均匀随机地从盒子中挑出一个球,记为A。不把A放回盒子,然后再从盒子中均匀随机地挑出一个球,记为B。
求出A上的数字严格大于B上的数字的概率是。
分析:记录没个数的个数,暴力枚举A,B,算出情况数,最后除以n*(n-1).
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define Mn 2510 #define Mm 2000005 #define mod 1000000007 #define CLR(a,b) memset((a),(b),sizeof((a))) #define CPY(a,b) memcpy ((a), (b), sizeof((a))) #pragma comment(linker, "/STACK:102400000,102400000") #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; int x,b[Mn]; int main() { int T; scanf("%d",&T); int n; while(T--) { CLR(b,0); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&x); b[x]++; } int ans=0; for(int i=300;i>0;i--) { int t=0; if(b[i]) for(int j=i-1;j>=0;j--) if(b[j])t+=b[i]*b[j]; if(t) ans+=t; } printf("%.6f\n",(double)ans/n/(n-1)); } return 0; }
题意:把n拆成k个不重复的正整数之和。输出这k个数最大乘积。
分析:我们可以知道连续的数乘积最大,记sum(a,k)=a+(a+1)+⋯+(a+k−1),可知k*(k+1)/2>n是不可拆分的,所以k最大10^5。
sum(a,k)<=n -> a*k+k*(k-1)<=n -> a<=n/k-(k-1)/2,可以求出a来,这时可能多出一些数,从后往前每个加1,加上多出来的数。
然后相乘。.
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define Mn 1001000 #define Mm 2000005 #define mod 1000000007 #define CLR(a,b) memset((a),(b),sizeof((a))) #define CPY(a,b) memcpy ((a), (b), sizeof((a))) #pragma comment(linker, "/STACK:102400000,102400000") #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; int main() { int t,n,k; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); if((ll)k*(k+1)/2>n) { printf("-1\n"); continue; } int a=(int)((double)n/k-((double)k-1)/2); int ha=n-a*k-k*(k-1)/2; ll ans=1; int ed=k-ha; for(int i=1;i<=ed;i++) { ans=(ans*(a+i-1))%mod; } for(int i=ed+1;i<=k;i++) { ans=(ans*(a+i))%mod; } printf("%I64d\n",ans); } return 0; }
题意:求每个点所在的连通集的大小和。
分析:令siz[i]表示以i为根的子树方案数,sum[i]表示以i为根对答案做的贡献。
sum[u]=((ll)sum[u]*(siz[v]+1))%mod; //之前子树的大小会变成*(siz[v]+1)种可行方案 因为每个元素都能在子结点的集合里出现一次
sum[u]=((ll)sum[u]+(ll)siz[u]*sum[v])%mod;//新的子树(y)大小会变成siz[u]*sum[v]种可行方案 因为每个子结点的元素都能在 u 的集合里出现一次。
siz[u]=((ll)siz[u]*(siz[v]+1))%mod;//子树大小会变成*(siz[v]+1)种
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define Mn 200010 #define Mm 300010 #define mod 1000000007 #define CLR(a,b) memset((a),(b),sizeof((a))) #define CPY(a,b) memcpy ((a), (b), sizeof((a))) #pragma comment(linker, "/STACK:102400000,102400000") #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; int read() { char c=getchar(); int re=0,f=1; while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();} return re*f; } struct edge { int v,next; }e[Mm]; int head[Mn],tot; void addedge(int u,int v) { e[tot].v=v; e[tot].next=head[u]; head[u]=tot++; } int n,m,siz[Mn],sum[Mn]; void dfs(int u,int fa) { siz[u]=1;sum[u]=1; for(int i=head[u];~i;i=e[i].next) { int v=e[i].v; if(v==fa) continue; dfs(v,u); sum[u]=((ll)sum[u]*(siz[v]+1))%mod; sum[u]=((ll)sum[u]+(ll)siz[u]*sum[v])%mod; siz[u]=((ll)siz[u]*(siz[v]+1))%mod; } } void init() { CLR(head,-1); tot=0; } int main() { int T; scanf("%d",&T); while(T--) { init(); n=read(); for(int i=2;i<=n;i++) { int u=read(); addedge(i,u); addedge(u,i); } dfs(1,0); ll ans=0; for(int i=1;i<=n;i++) ans=(ans+sum[i])%mod; cout<<ans<<endl; } return 0; }