正睿20NOIp前冲刺day13
估分:100+40+35+30=205
实际:100+20+15+30=175
T1:
数位DP,打表就可以发现规律
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 typedef long long LL; 8 9 inline LL read() 10 { 11 LL x = 0, f = 0; 12 char ch = getchar(); 13 while (!isdigit(ch)) f = ch == '-', ch = getchar(); 14 while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); 15 return f ? -x : x; 16 } 17 18 const int popc[300] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; 19 20 int popcount(LL x) { return popc[x & 0xff] + popc[(x >> 8) & 0xff] + popc[(x >> 16) & 0xff] + popc[(x >> 24) & 0xff] + popc[(x >> 32) & 0xff] + popc[(x >> 40) & 0xff] + popc[(x >> 48) & 0xff] + popc[(x >> 56) & 0xff]; } 21 22 struct Exactly 23 { 24 LL f[110]; 25 26 void work(LL n) 27 { 28 f[0] = 1; 29 for (int i = 1; i <= 65; i++) f[i] = 2 * f[i - 1] + 1; 30 31 LL ans = 0; 32 for (int i = 0; n; n >>= 1, i++) if (n & 1) ans += f[i]; 33 printf("%lld", ans); 34 } 35 }E; 36 37 int main() 38 { 39 LL n = read(); 40 if (n <= 1000000) 41 { 42 LL ans = 0; 43 for (LL i = 0; i < n; i++) ans += popcount(i ^ (i + 1)); 44 printf("%lld", ans); 45 } 46 else E.work(n), exit(0); 47 }
T2:
脑抽把n=1的情况改了(什么时候改的都不知道),丢了20pts
先看n=2,x≤1000的情况,f(i,j)表示第一种颜色有i个球,第二种颜色有j个球,用一个筹码能换来多少个筹码,首先f(0,1)=f(1,0)=2。然后一个f(i,j),可以拿一个球变成f(i-1,j)或f(i,j-1),但要最优情况,所以只有无论变成哪种情况,最后得的筹码都不变才最优,否则幕后黑手一定会把状态变成最后得的筹码最少的状态。假设a=f(i-1,j),b=f(i,j-1),押了x个筹码在第一种颜色的球上,剩下的(1-x)就押在第二种颜色的球上,我们就要求ax=b(1-x),则x=b/(a+b),那么f(i,j)就等于2*b/(a+b)*a。
之后看优化这个DP,设$g(i,j)=\frac{f(i,j)}{2^{i+j}}$,那么g的转移方程就是$g(i,j)=\frac{g(i-1,j)g(i,j-1)}{g(i-1,j)+g(i,j-1)}$,两边取倒后就变成$\frac{1}{g(i,j)}=\frac{g(i-1,j)g(i,j-1)}{g(i-1,j)+g(i,j-1)}=\frac{1}{g(i-1,j)}+\frac{1}{g(i,j-1)}$,可以发$\frac{1}{f(i,j)}$其实就是在平面上走,只能往上或往右走,从(0,0)走到(i,j)的方案数,也就是$\binom{i+j}{i}$,答案就是$\frac{2^{i+j}}{\binom{i+j}{i}}$
之后再考虑n>2的时候怎么做,也可以写出和n=2一样的转移方程,只不过是n维的,设$f(x_{1},x_{2},x_{3},x_{4},x_{5},...,x_{n})$表示从(0,0,0,0,0,...,0)走到$x_{1},x_{2},x_{3},x_{4},x_{5},...,x_{n}$的方案数,所以$f(x_{1},x_{2},x_{3},x_{4},x_{5},...,x_{n})=\frac{\left (\sum_{i=1}^{n}x_{i} \right )!}{\prod_{i=1}^{n}x_{i}!}$,之后就能算出答案了。
搞不懂他们写的贪心为什么能过
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 inline int read() 8 { 9 int x = 0, f = 0; 10 char ch = getchar(); 11 while (!isdigit(ch)) f = ch == '-', ch = getchar(); 12 while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); 13 return f ? -x : x; 14 } 15 16 const int N = 1000010; 17 const int mod = 998244353; 18 19 int n; 20 int a[N], fac[N], inv[N]; 21 22 inline int qpow(int a, int k, int mod) 23 { 24 int res = 1; 25 while (k) 26 { 27 if (k & 1) res = 1ll * res * a % mod; 28 a = 1ll * a * a % mod; 29 k >>= 1; 30 } 31 return res; 32 } 33 34 void init(int s) 35 { 36 fac[0] = 1; 37 for (int i = 1; i <= s; i++) fac[i] = 1ll * fac[i - 1] * i % mod; 38 inv[s] = qpow(fac[s], mod - 2, mod); 39 for (int i = s - 1; ~i; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod; 40 } 41 42 int main() 43 { 44 n = read(); 45 int sum = 0; 46 for (int i = 1; i <= n; i++) a[i] = read(), sum += a[i]; 47 48 init(sum); 49 50 int ans = 1ll * qpow(n, sum, mod) * inv[sum] % mod; 51 52 for (int i = 1; i <= n; i++) ans = 1ll * ans * fac[a[i]] % mod; 53 printf("%d", ans); 54 }
T3:
也不知道暴力哪错了,换种写法就对了,暴力去了20pts
T4:
30pts暴力写完就跑
总结:
以后还是留个十几分钟多检查下代码吧。二三题都是推出正解的公式但不会算,之后要多补数学。还有为什么二题贼简单的贪心能过啊,感性证明吗
浙公网安备 33010602011771号