https://www.nowcoder.com/acm/contest/173#question
T1:https://www.nowcoder.com/acm/contest/173/A
题意概述:对于一个序列,求把序列中的每一个数删去后的新方差*长度的平方.
良心T1,送分送温暖,把方差的式子化开,O(n)就可以解决.
1 # include <cstdio> 2 # include <iostream> 3 # define R register int 4 5 using namespace std; 6 7 const int maxn=100005; 8 int n; 9 long long a[maxn],s,ss,x,y,z; 10 11 int main() 12 { 13 scanf("%d",&n); 14 for (R i=1;i<=n;++i) 15 scanf("%lld",&a[i]),s+=a[i],ss+=a[i]*a[i]; 16 for (R i=1;i<=n;++i) 17 { 18 x=(ss-a[i]*a[i])*(n-1); 19 y=(s-a[i])*(s-a[i]); 20 if(i!=n) printf("%lld ",x-y); 21 } 22 printf("%lld ",x-y); 23 return 0; 24 }
T2:https://www.nowcoder.com/acm/contest/173/B
题意概述:$N$个小朋友围成一圈,你有无穷个糖果,想把其中一些分给他们。从某个小朋友开始,我们顺时针给他们标号为$1~N$。第$i$个小朋友可以得到至多$a_i$,至少$1$个糖果。问,有多少种分配方案使得每一对相邻的小朋友拿到的糖果数不同。答案对$10^9+7$取模。
良心的T1反衬了T2的不良心.这道题在拿部分分的道路上设置了层层阻碍,比如说前十分的$a_i$实测极大,根本不能用后$30$分的方法来做.
考虑一个简单的$dp_ij$表示从$1$号小朋友开始发糖,发到第$i$个,且给第$i$个发了$j$个的方案数,因为$n$个人围成一个圈,所以要注意第$1$个人和第$n$个人的糖数也不能相同,可以枚举第一个人拿到的数量.
对于$a_i$全部相等的情况,可以先不考虑首尾不相等的情况,用$f_i$表示$i$个人发糖的方案数,$f_i=m*(m-1)^{i-1}$,如果首尾相同,则可以把这两个人视为同一个,这样的方案数就成了$f_{i-1}$,递推求解,然而忘开$long long$导致分数只有30.
1 # include <cstdio> 2 # include <iostream> 3 # include <cstring> 4 # define mod 1000000007 5 # define R register int 6 7 using namespace std; 8 9 const int maxn=1000005; 10 int n,m; 11 int a[maxn]; 12 long long dp[105][105],s[105],ans,f[maxn],t=1; 13 14 int main() 15 { 16 scanf("%d",&n); 17 for (R i=1;i<=n;++i) 18 scanf("%d",&a[i]); 19 if(n>100) 20 { 21 m=a[1]; 22 f[1]=m%mod; 23 f[2]=(1LL)*m*(m-1)%mod; 24 t=(1LL)*(m-1)*(m-1)%mod; 25 for (R i=3;i<=n;++i) 26 { 27 f[i]=((((1LL)*m*t-f[i-1])%mod+mod)%mod); 28 t=(1LL)*t*(m-1)%mod; 29 } 30 printf("%lld",f[n]); 31 return 0; 32 } 33 for (R i=1;i<=a[1];++i) 34 { 35 memset(dp,0,sizeof(dp)); 36 memset(s,0,sizeof(s)); 37 dp[1][i]=1; 38 s[1]=1; 39 for (R j=2;j<=n;++j) 40 { 41 for (R k=1;k<=a[j];++k) 42 { 43 dp[j][k]=((s[j-1]-dp[j-1][k])%mod+mod)%mod; 44 if(j==n&&k==i) continue; 45 s[j]=(s[j]+dp[j][k])%mod; 46 } 47 } 48 ans=(ans+s[n])%mod; 49 } 50 printf("%lld",ans); 51 return 0; 52 }
T3:https://www.nowcoder.com/acm/contest/173/C
题意比较复杂...
打了一个搜索,得了十分.
1 # include <cstdio> 2 # include <iostream> 3 # define R register int 4 5 using namespace std; 6 7 const int maxs=300005; 8 int n,m,k,x; 9 int a[maxs]; 10 bool f=false; 11 int s[maxs]; 12 int t[maxs],ans[maxs]; 13 14 void check () 15 { 16 for (R i=1;i<=k;++i) 17 for (R j=1;j<=k;++j) 18 if(s[ t[i]|t[j] ]==false) return; 19 f=true; 20 for (R i=1;i<=k;++i) 21 ans[ t[i] ]=1; 22 } 23 24 void dfs (int las,int cnt) 25 { 26 if(f) return ; 27 if(cnt==k) check(); 28 else 29 { 30 for (R i=las;i<=(1<<n)-1;++i) 31 { 32 if(s[i]) continue; 33 s[i]=true; 34 t[cnt+1]=i; 35 dfs(i+1,cnt+1); 36 s[i]=false; 37 if(f) return ; 38 } 39 } 40 } 41 42 int main() 43 { 44 scanf("%d%d%d",&n,&m,&k); 45 for (R i=1;i<=m;++i) 46 scanf("%d",&a[i]),s[ a[i] ]=true; 47 for (R i=1;i<=m;++i) 48 for (R j=1;j<i;++j) 49 { 50 if(s[ a[i]|a[j] ]) continue; 51 a[++m]=a[i]|a[j]; 52 s[ a[i]|a[j] ]=true; 53 } 54 if(m>k) 55 { 56 printf("-1"); 57 return 0; 58 } 59 for (R i=1;i<=m;++i) 60 t[i]=a[i]; 61 dfs(1,m); 62 if(f) 63 for (R i=1;i<=(1<<n)-1;++i) 64 printf("%d",ans[i]); 65 else 66 printf("-1"); 67 return 0; 68 }
这道题的正解很神奇,是一个状压dp,给每个元素一个优先级,则每个集合的特征就是这个集合中优先级最高的元素,把同样特征的集合都给一个人肯定是合法的,事实上也是构成答案的一个必需条件,问题就在于怎么分使得正好有一部分特征的集合数量总和等于要求的数量.当$k$等于$0$时,可以用$lowbit$来定义集合的优先级,这样每个优先级的集合个数就正好是$2^k$,且不会重复,显然可以用他们凑出任意所需大小的数字来.
---shzr