C:Half and Half
几个if语句贪心算一算就好了
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int a,b,c,x,y,t; 5 int main() 6 { 7 scanf_s("%d%d%d%d%d",&a,&b,&c,&x,&y);c*=2; 8 a=min(a,c);b=min(b,c); 9 if (a+b<=c) printf("%d\n",x*a+y*b); 10 else t=min(x,y),printf("%d\n",t*c+(x-t)*a+(y-t)*b); 11 return 0; 12 }
D:Static Sushi
这是个环形吧台,所以可以正着走、倒着走、正着走再倒着走、倒着走再正着走。
记录一个前缀和即可。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int N=100005; 6 int n,pos1,pos2; 7 ll C,x[N],w[N],sum,Max,Max1[N],Max2[N]; 8 int main() 9 { 10 scanf("%d%lld",&n,&C); 11 for (int i=1;i<=n;i++) scanf("%lld%lld",&x[i],&w[i]); 12 for (int i=1;i<=n;i++) 13 sum+=w[i],Max1[i]=max(Max1[i-1],sum-x[i]); 14 sum=0; 15 for (int i=n;i>=1;i--) 16 sum+=w[i],Max2[i]=max(Max2[i+1],sum-(C-x[i])); 17 Max=max(Max1[n],Max2[1]); 18 sum=0; 19 for (int i=1;i<=n;i++) sum+=w[i],Max=max(Max,Max2[i+1]+sum-x[i]*2); 20 sum=0; 21 for (int i=n;i>=1;i--) sum+=w[i],Max=max(Max,Max1[i-1]+sum-(C-x[i])*2); 22 printf("%lld\n",Max); 23 return 0; 24 }
晚了五分钟开,名次掉飞真是不开心。。。
E:Everything on it
可以选择任意碗拉面,每碗的配料组合必须不同。配料一共有$n$种,$2^n$种组合。问有多少种选拉面的方案可以使得每一种配料都至少出现了两次?$n<=3000$。
容斥。设f[i]为至少有i种配料出现次数<=1的方案数。那么$ans=\sum_{i=0}^{n}((-1)^i*f[i]*C(n,i))$。
怎么求f[i]?比较麻烦的地方是一个数中有多个配料,怎么来保证选取的i个配料必然出现<=1次?
考虑第二类斯特灵数的前缀和s[i][j]表示<=i个元素分到非空的j的集合的方案数。
即i种配料要么不出现,要么被分到集合中,同一个集合的出现在同一个二进制数里,有$2^ {n-i}$种方案(其他n-i种随意,这一个集合中的同时出现)。有j个集合,不同集合之间独立,就有$(2^{n-i})^j$种方案。其余n-i种配料的组合任意,因此$f[i]=\sum_{j=0}^{i}s[i][j]*2^{(n-i)*j}*2^{2^{n-i}}$。
1 #include<cstdio> 2 using namespace std; 3 typedef long long ll; 4 const int N=3005; 5 int ans,n,mod,jc[N],inv[N],s[N][N],f[N],pw[N*N]; 6 int ksm(int x,int y,int mod) 7 { 8 int res=1; 9 while (y) {if (y&1) res=(ll)res*x%mod;x=(ll)x*x%mod;y>>=1;} 10 return res; 11 } 12 int c(int n,int m) {return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;} 13 int main() 14 { 15 scanf("%d%d",&n,&mod); 16 jc[0]=jc[1]=inv[0]=inv[1]=pw[0]=1; 17 for (int i=2;i<=n;i++) jc[i]=(ll)jc[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 18 for (int i=2;i<=n;i++) inv[i]=(ll)inv[i-1]*inv[i]%mod; 19 for (int i=1;i<=n*n;i++) pw[i]=(ll)pw[i-1]*2%mod; 20 for (int i=0;i<=n;i++) s[i][0]=1;//初始化,都有一种可能分到0个集合 21 for (int i=1;i<=n;i++) 22 for (int j=1;j<=i;j++) 23 s[i][j]=((ll)s[i-1][j-1]+(ll)(j+1)*s[i-1][j]%mod)%mod;//<=i个元素分入j个非空集合的方案数 24 for (int i=0;i<=n;i++) 25 { 26 for (int j=0;j<=i;j++) f[i]=((ll)f[i]+(ll)s[i][j]*pw[(n-i)*j]%mod)%mod; 27 f[i]=(ll)f[i]*ksm(2,ksm(2,n-i,mod-1),mod)%mod; 28 } 29 for (int i=0;i<=n;i++) 30 if (i&1) ans=((ll)ans-(ll)c(n,i)*f[i]%mod+mod)%mod; 31 else ans=((ll)ans+(ll)c(n,i)*f[i]%mod)%mod; 32 printf("%d\n",ans); 33 return 0; 34 }
F:不会,待填坑