五月の诈尸笔记
最近状态超差。省赛惶恐。
强行插队的后果就是主刀沉迷考研副刀沉迷英语辅助沉迷力学。
趁着马上到来的公费旅游调养一下生息。然而马上要考试了。
5.7
xdu 1158 Orz Fatality
不是很懂数学。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 const LL mod = 1e9 + 7; 6 const int maxn = 1e7 + 10; 7 LL fac[maxn]; 8 9 LL qpow(LL a, int b) 10 { 11 LL ret = 1LL; 12 while(b) 13 { 14 if(b & 1) ret = ret * a % mod; 15 a = a * a % mod; 16 b >>= 1; 17 } 18 return ret; 19 } 20 21 LL inv(LL x) 22 { 23 return qpow(x, mod - 2); 24 } 25 26 int main(void) 27 { 28 fac[0] = 1LL; 29 for(int i = 1; i < maxn; i++) fac[i] = fac[i-1] * i % mod; 30 LL x, y, k; 31 while(~scanf("%lld %lld %lld", &x, &y, &k)) 32 { 33 if(k > y) puts("0"); 34 else if(k == y) puts("1"); 35 else 36 { 37 if(x + y >= maxn || x + k >= maxn) while(1); 38 LL ans = fac[x+y] * inv(fac[x+k]) % mod * inv(fac[y-k]) % mod; 39 printf("%lld\n", ans); 40 } 41 } 42 return 0; 43 }
xdu 1148 修理OJ II
不是很懂数学again。
不懂题解最后一步怎么推的后来自己CRT出来式子不太一样也过了。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 typedef long long LL; 7 8 LL Eular(LL n) 9 { 10 LL ret = n; 11 for(LL i = 2; i * i <= n; i++) 12 { 13 if(n % i == 0) 14 { 15 ret -= ret / i; 16 while(n % i == 0) n /= i; 17 } 18 } 19 if(n > 1) ret -= ret / n; 20 return ret; 21 } 22 23 LL qpow(LL a, LL b) 24 { 25 LL ret = 1LL; 26 while(b) 27 { 28 if(b & 1) ret = ret * a; 29 a = a * a; 30 b >>= 1; 31 } 32 return ret; 33 } 34 35 LL qpow(LL a, LL b, LL mod) 36 { 37 LL ret = 1LL; 38 while(b) 39 { 40 if(b & 1) ret = ret * a % mod; 41 a = a * a % mod; 42 b >>= 1; 43 } 44 return ret; 45 } 46 47 int main(void) 48 { 49 LL a, b, c, y; 50 while(~scanf("%lld %lld %lld %lld", &a, &b, &c, &y)) 51 { 52 LL tmp = a, f = y, g = 1LL, t0 = 0LL; 53 for(LL i = 2; i * i <= tmp; i++) 54 { 55 if(tmp % i == 0) 56 { 57 LL c1 = 0, c2 = 0; 58 while(tmp % i == 0) tmp /= i, c1++; 59 while(f % i == 0) f /= i, g *= i, c2++; 60 t0 = max(t0, (c2 + c1 - 1) / c1); 61 } 62 } 63 if(tmp > 1) 64 { 65 LL c2 = 0; 66 while(f % tmp == 0) f /= tmp, g *= tmp, c2++; 67 t0 = max(t0, c2); 68 } 69 if(log(b) < log(t0) / c) 70 { 71 LL e = qpow(b, c); 72 printf("%lld\n", qpow(a, e, y)); 73 } 74 else 75 { 76 LL pf = Eular(f); 77 LL ans = qpow(a, qpow(b, c, pf), y) * qpow(g, pf, y) % y; 78 printf("%lld\n", ans); 79 } 80 } 81 return 0; 82 }
5.8
HDU 3037 Saving Beans
bin神模板。
1 // HDU 3037 Saving Beans 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 typedef long long LL; 6 const int maxn = 1e5 + 10; 7 LL fac[maxn]; 8 9 LL qpow(LL a, LL b, LL mod) 10 { 11 LL ret = 1LL; 12 while(b) 13 { 14 if(b & 1) ret = ret * a % mod; 15 a = a * a % mod; 16 b >>= 1; 17 } 18 return ret; 19 } 20 21 LL inv(LL x, LL mod) 22 { 23 return qpow(x, mod - 2, mod); 24 } 25 26 LL Lucas(LL n, LL m, LL mod) 27 { 28 LL ret = 1LL; 29 while(n && m) 30 { 31 LL a = n % mod, b = m % mod; 32 if(a < b) return 0; 33 ret = ret * fac[a] % mod * inv(fac[b] * fac[a-b] % mod, mod) % mod; 34 n /= mod, m /= mod; 35 } 36 return ret; 37 } 38 39 int main(void) 40 { 41 int T; 42 scanf("%d", &T); 43 while(T--) 44 { 45 LL n, m, p; 46 scanf("%I64d %I64d %I64d", &n, &m, &p); 47 fac[0] = 1LL; 48 for(int i = 1; i <= p; i++) fac[i] = fac[i-1] * i % p; 49 printf("%I64d\n", Lucas(n+m, n, p)); 50 } 51 return 0; 52 }
xdu 1057 卡尔的技能
原来叫 可重复组合数 阿。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 const int maxn = 1e4 + 10; 6 const LL mod = 10007; 7 LL fac[maxn]; 8 9 LL qpow(LL a, LL b) 10 { 11 LL ret = 1LL; 12 while(b) 13 { 14 if(b & 1) ret = ret * a % mod; 15 a = a * a % mod; 16 b >>= 1; 17 } 18 return ret; 19 } 20 21 LL inv(LL x) 22 { 23 return qpow(x, mod - 2); 24 } 25 26 LL Lucas(LL n, LL m) 27 { 28 LL ret = 1LL; 29 while(n && m) 30 { 31 LL a = n % mod, b = m % mod; 32 if(a < b) return 0; 33 ret = ret * fac[a] % mod * inv(fac[b] * fac[a-b] % mod) % mod; 34 n /= mod, m /= mod; 35 } 36 return ret; 37 } 38 39 int main(void) 40 { 41 fac[0] = 1LL; 42 for(int i = 1; i <= mod; i++) fac[i] = fac[i-1] * i % mod; 43 LL n, m; 44 while(~scanf("%lld %lld", &n, &m)) printf("%lld\n", Lucas(n+m-1, m)); 45 return 0; 46 }
5.10
PKU CAMPUS 2016 D Extracurricular Sports
不懂构造。昂神思路。bin神模板。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int MAXN = 9999; 7 const int MAXSIZE = 1010; 8 const int DLEN = 4; 9 10 class BigNum 11 { 12 private: 13 int a[500]; //可以控制大数的位数 14 int len; 15 public: 16 BigNum() {len = 1; memset(a, 0, sizeof(a));} //构造函数 17 BigNum(const int); //将一个int类型的变量转化成大数 18 BigNum(const char *); //将一个字符串类型的变量转化为大数 19 BigNum(const BigNum &); //拷贝构造函数 20 BigNum & operator = (const BigNum &); //重载赋值运算符,大数之间进行赋值运算 21 friend istream & operator >> (istream &, BigNum &); //重载输入运算符 22 friend ostream & operator << (ostream &, BigNum &); //重载输出运算符 23 BigNum operator + (const BigNum &)const; //重载加法运算符,两个大数之间的相加运算 24 BigNum operator - (const BigNum &)const; //重载减法运算符,两个大数之间的相减运算 25 BigNum operator * (const BigNum &)const; //重载乘法运算符,两个大数之间的相乘运算 26 BigNum operator / (const int &)const; //重载除法运算符,大数对一个整数进行相除运算 27 BigNum operator ^ (const int &)const; //大数的n次方运算 28 int operator % (const int &)const; //大数对一个int类型的变量进行取模运算 29 bool operator > (const BigNum & T)const; //大数和另一个大数的大小比较 30 bool operator > (const int & t)const; //大数和一个int类型的变量的大小比较 31 void print(); //输出大数 32 }; 33 34 BigNum::BigNum(const int b) //将一个int类型的变量转化为大数 35 { 36 int c, d = b; 37 len = 0; 38 memset(a, 0, sizeof(a)); 39 while(d > MAXN) 40 { 41 c = d - (d / (MAXN + 1)) * (MAXN + 1); 42 d = d / (MAXN + 1); 43 a[len++] = c; 44 } 45 a[len++] = d; 46 } 47 48 BigNum::BigNum(const char * s) //将一个字符串类型的变量转化为大数 49 { 50 int t, k, index, L, i; 51 memset(a, 0, sizeof(a)); 52 L = strlen(s); 53 len = L / DLEN; 54 if(L % DLEN) len++; 55 index = 0; 56 for(i = L - 1; i >= 0; i -= DLEN) 57 { 58 t = 0; 59 k = i - DLEN + 1; 60 if(k < 0) k = 0; 61 for(int j = k; j <= i; j++) 62 t = t * 10 + s[j] - '0'; 63 a[index++] = t; 64 } 65 } 66 67 BigNum::BigNum(const BigNum & T): len(T.len) //拷贝构造函数 68 { 69 int i; 70 memset(a, 0, sizeof(a)); 71 for(i = 0; i < len; i++) 72 a[i] = T.a[i]; 73 } 74 75 BigNum & BigNum::operator = (const BigNum & n) //重载赋值运算符,大数之间赋值运算 76 { 77 int i; 78 len = n.len; 79 memset(a, 0, sizeof(a)); 80 for(i = 0; i < len; i++) 81 a[i] = n.a[i]; 82 return * this; 83 } 84 85 istream & operator >> (istream & in, BigNum & b) 86 { 87 char ch[MAXSIZE*4]; 88 int i = -1; 89 in >> ch; 90 int L = strlen(ch); 91 int count = 0, sum = 0; 92 for(i = L - 1; i >= 0; ) 93 { 94 sum = 0; 95 int t = 1; 96 for(int j = 0; j < 4 && i >= 0; j++, i--, t *= 10) 97 { 98 sum += (ch[i] - '0') * t; 99 } 100 b.a[count] = sum; 101 count++; 102 } 103 b.len = count++; 104 return in; 105 } 106 107 ostream & operator << (ostream & out, BigNum & b) //重载输出运算符 108 { 109 int i; 110 cout << b.a[b.len-1]; 111 for(i = b.len - 2; i >= 0; i--) 112 { 113 printf("%04d", b.a[i]); 114 } 115 return out; 116 } 117 118 BigNum BigNum::operator + (const BigNum & T) const //两个大数之间的相加运算 119 { 120 BigNum t(*this); 121 int i, big; 122 big = T.len > len ? T.len : len; 123 for(i = 0; i < big; i++) 124 { 125 t.a[i] += T.a[i]; 126 if(t.a[i] > MAXN) 127 { 128 t.a[i+1]++; 129 t.a[i] -= MAXN + 1; 130 } 131 } 132 if(t.a[big] != 0) 133 t.len = big + 1; 134 else t.len = big; 135 return t; 136 } 137 138 BigNum BigNum::operator - (const BigNum & T) const //两个大数之间的相减运算 139 { 140 int i, j, big; 141 bool flag; 142 BigNum t1, t2; 143 if(*this > T) 144 { 145 t1 = *this; 146 t2 = T; 147 flag = 0; 148 } 149 else 150 { 151 t1 = T; 152 t2 = *this; 153 flag = 1; 154 } 155 big = t1.len; 156 for(i = 0; i < big; i++) 157 { 158 if(t1.a[i] < t2.a[i]) 159 { 160 j = i + 1; 161 while(t1.a[j] == 0) 162 j++; 163 t1.a[j--]--; 164 while(j > i) 165 t1.a[j--] += MAXN; 166 t1.a[i] += MAXN + 1 - t2.a[i]; 167 } 168 else t1.a[i] -= t2.a[i]; 169 } 170 t1.len = big; 171 while(t1.a[len-1] == 0 && t1.len > 1) 172 { 173 t1.len--; 174 big--; 175 } 176 if(flag) 177 t1.a[big-1] = 0 - t1.a[big-1]; 178 return t1; 179 } 180 181 BigNum BigNum::operator * (const BigNum & T) const //两个大数之间的相乘 182 { 183 BigNum ret; 184 int i, j, up; 185 int temp, temp1; 186 for(i = 0; i < len; i++) 187 { 188 up = 0; 189 for(j = 0; j < T.len; j++) 190 { 191 temp = a[i] * T.a[j] + ret.a[i+j] + up; 192 if(temp > MAXN) 193 { 194 temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); 195 up = temp / (MAXN + 1); 196 ret.a[i+j] = temp1; 197 } 198 else 199 { 200 up = 0; 201 ret.a[i+j] = temp; 202 } 203 } 204 if(up != 0) 205 ret.a[i+j] = up; 206 } 207 ret.len = i + j; 208 while(ret.a[ret.len-1] == 0 && ret.len > 1) ret.len--; 209 return ret; 210 } 211 212 BigNum BigNum::operator / (const int & b) const //大数对一个整数进行相除运算 213 { 214 BigNum ret; 215 int i, down = 0; 216 for(i = len - 1; i >= 0; i--) 217 { 218 ret.a[i] = (a[i] + down * (MAXN + 1)) / b; 219 down = a[i] + down * (MAXN + 1) - ret.a[i] * b; 220 } 221 ret.len = len; 222 while(ret.a[ret.len-1] == 0 && ret.len > 1) 223 ret.len--; 224 return ret; 225 } 226 227 int BigNum::operator % (const int & b) const //大数对一个 int类型的变量进行取模 228 { 229 int i, d = 0; 230 for(i = len - 1; i >= 0; i--) 231 d = ((d * (MAXN + 1)) % b + a[i]) % b; 232 return d; 233 } 234 235 BigNum BigNum::operator ^ (const int & n) const //大数的n次方运算 236 { 237 BigNum t, ret(1); 238 int i; 239 if(n < 0) exit(-1); 240 if(n == 0) return 1; 241 if(n == 1) return *this; 242 int m = n; 243 while(m > 1) 244 { 245 t = *this; 246 for(i = 1; (i << 1) <= m; i <<= 1) 247 t = t * t; 248 m -= i; 249 ret = ret * t; 250 if(m == 1) ret = ret * (*this); 251 } 252 return ret; 253 } 254 255 bool BigNum::operator > (const BigNum & T) const //大数和另一个大数的大小比较 256 { 257 int ln; 258 if(len > T.len) return true; 259 else if(len == T.len) 260 { 261 ln = len - 1; 262 while(a[ln] == T.a[ln] && ln >= 0) 263 ln--; 264 if(ln >= 0 && a[ln] > T.a[ln]) 265 return true; 266 else 267 return false; 268 } 269 else 270 return false; 271 } 272 273 bool BigNum::operator > (const int & t) const //大数和一个int类型的变量的大小比较 274 { 275 BigNum b(t); 276 return *this > b; 277 } 278 279 void BigNum::print() //输出大数 280 { 281 int i; 282 printf("%d", a[len-1]); 283 for(i = len - 2; i >= 0; i--) 284 printf("%04d", a[i]); 285 printf("\n"); 286 } 287 288 int main(void) 289 { 290 int T; 291 scanf("%d", &T); 292 while(T--) 293 { 294 int n; 295 scanf("%d", &n); 296 if(n == 2) {puts("-1"); continue;} 297 BigNum N[300]; 298 BigNum two = BigNum(2), three = BigNum(3); 299 N[1] = BigNum(1), N[2] = two, N[3] = three; 300 if(n >= 4) N[3] = BigNum(6), N[4] = BigNum(9); 301 for(int i = 5; i <= n; i++) 302 { 303 for(int j = 3; j < n; j++) N[j] = N[j] * two; 304 N[i] = three; 305 } 306 for(int i = 1; i <= n; i++) N[i].print(); 307 } 308 return 0; 309 }
5.12
PKU CAMPUS 2016 H Magical Balls
昨天式子推错坑一天。今天还好发现是lld了。不然又要坑一天。
num[i+1] = num[i] * (u[i+1] + d[i+1] + l[i+1] + r[i+1] + 1)
sum[i+1] = sum[i] * (u[i+1] + d[i+1] + l[i+1] + r[i+1] + 1) + num[i] * (u[i+1] + r[i+1] - l[i+1] - d[i+1])
矩乘压一下。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long LL; 6 const LL mod = 1e9 + 7; 7 const int maxn = 3; 8 9 struct Matrix 10 { 11 LL m[maxn][maxn]; 12 Matrix(){memset(m, 0, sizeof(m));} 13 void E(){for(int i = 0; i < maxn; i++) m[i][i] = 1;} 14 }; 15 16 Matrix M_mul(Matrix a, Matrix b) 17 { 18 Matrix ret; 19 for(int i = 0; i < maxn; i++) 20 for(int j = 0; j < maxn; j++) 21 for(int k = 0; k < maxn; k++) 22 ret.m[i][j] = ( ret.m[i][j] + (a.m[i][k] * b.m[k][j]) % mod ) % mod; 23 return ret; 24 } 25 26 Matrix M_qpow(Matrix P, LL n) 27 { 28 Matrix ret; 29 ret.E(); 30 while(n) 31 { 32 if(n & 1LL) ret = M_mul(ret, P); 33 n >>= 1LL; 34 P = M_mul(P, P); 35 } 36 return ret; 37 } 38 39 int main(void) 40 { 41 int T; 42 scanf("%d", &T); 43 while(T--) 44 { 45 LL N, M, x0, y0; 46 scanf("%lld %lld %lld %lld", &N, &M, &x0, &y0); 47 LL q = N / M, R = N % M; 48 Matrix A, B; 49 A.E(), B.E(); 50 for(int i = 1; i <= M; i++) 51 { 52 LL u, d, l, r; 53 scanf("%lld %lld %lld %lld", &u, &d, &l, &r); 54 Matrix tmp; 55 tmp.m[1][1] = tmp.m[2][2] = (u + r + d + l + 1LL) % mod; 56 tmp.m[2][1] = (u + r - d - l + mod) % mod; 57 A = M_mul(tmp, A); 58 if(i <= R) B = M_mul(tmp, B); 59 } 60 Matrix P = M_mul(B, M_qpow(A, q)); 61 LL ans = (P.m[2][1] + (x0 % mod + y0 % mod + mod + mod) % mod * P.m[2][2] % mod) % mod; 62 printf("%lld\n", ans); 63 } 64 return 0; 65 }
5.13
BZOJ 2301 [HAOI2011]Problem b
不是很懂数学。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 1e6 + 10; 7 int np[maxn], pr[maxn], mu[maxn]; 8 int sum[maxn]; 9 10 void Mobius() 11 { 12 memset(np, 0, sizeof(np)); 13 mu[1] = 1; 14 int tot = 0; 15 for(int i = 2; i < maxn; i++) 16 { 17 if(!np[i]) 18 { 19 pr[tot++] = i; 20 mu[i] = -1; 21 } 22 for(int j = 0; j < tot; j++) 23 { 24 if(i * pr[j] >= maxn) break; 25 np[i*pr[j]] = 1; 26 if(i % pr[j] == 0) 27 { 28 mu[i*pr[j]] = 0; 29 break; 30 } 31 else mu[i*pr[j]] = -mu[i]; 32 } 33 } 34 } 35 36 int cal(int n, int m) 37 { 38 int ret = 0, pre; 39 if(n > m) swap(n, m); 40 for(int i = 1; i <= n; i = pre + 1) 41 { 42 pre = min(n / (n / i), m / (m / i)); 43 ret += (n / i) * (m / i) * (sum[pre] - sum[i-1]); 44 } 45 return ret; 46 } 47 48 int main(void) 49 { 50 Mobius(); 51 for(int i = 1; i < maxn; i++) sum[i] = sum[i-1] + mu[i]; 52 int n; 53 scanf("%d", &n); 54 while(n--) 55 { 56 int a, b, c, d, k; 57 scanf("%d %d %d %d %d", &a, &b, &c, &d, &k); 58 int ans = cal(b / k, d / k) - cal(b / k, (c - 1) / k) - cal((a - 1) / k, d / k) + cal((a - 1) / k, (c - 1) / k); 59 printf("%d\n", ans); 60 } 61 return 0; 62 }
5.17
HZAU 1015 LCS
抄标程。
先预处理f[i][j]为a串前i,b串前j的最长公共后缀。
要求的是dp[i][j]为a串前i,b串前j的每部分不小于k的LCS。
这个不好直接推。所以引入一个opt[i][j][p]为取了a串i位置,b串j位置结尾,往前长度为p的一个公共串的LCS。
考虑opt的转移。如果p大于k,那么最优的opt其实就是前面取了i-1,j-1位置,后面再加一个相同字符。
①转移式是opt[i][j][p] = opt[i-1][j-1][p-1]+1,然后就可以枚举所有大于k的p推这个。
再考虑p等于k,这时opt[i-1][j-1][p-1]就没有了。
相当于i-k,j-k的答案我们已经算好了,后面又加上一段k的公共串。
②转移式是opt[i][j][k] = dp[i-k][j-k] + k。
上面因为要枚举p,复杂度就n^3爆炸了。于是把opt这个状态压一压。
opt[i][j]表示取a串i位置,b串j位置结尾,p取遍所有大于等于k的数的最优值。
(这里的opt[i][j]相当于上面的max{opt[i][j][p]}取遍p)
那么同样的分两类转移,如果i,j位置的f等于k,那么只能按②转移。即opt[i][j] = dp[i-k][j-k] + k。
如果f>k,考虑②同时也要考虑①,即opt[i][j] = opt[i-1][j-1] + 1。两者取优。
opt算好了。就可以推dp了。
如果i,j位置不取,那么相当于没有,此时dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
如果取了,就是dp[i][j] = opt[i][j],也是两者取优。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int k, f[2222][2222], dp[2222][2222], opt[2222][2222]; 6 char a[2222], b[2222]; 7 8 int main(void) 9 { 10 while(~scanf("%s %s %d", a + 1, b + 1, &k)) 11 { 12 13 memset(f, 0, sizeof(f)); 14 memset(dp, 0, sizeof(dp)); 15 memset(opt, 0, sizeof(opt)); 16 17 int la = strlen(a + 1), lb = strlen(b + 1); 18 19 for(int i = 1; i <= la; i++) 20 for(int j = 1; j <= lb; j++) 21 f[i][j] = (a[i] == b[j]) ? (f[i-1][j-1] + 1) : 0; 22 23 for(int i = 1; i <= la; i++) 24 { 25 for(int j = 1; j <= lb; j++) 26 { 27 if(f[i][j] >= k) 28 { 29 opt[i][j] = max(opt[i][j], dp[i-k][j-k] + k); 30 if(f[i][j] > k) opt[i][j] = max(opt[i][j], opt[i-1][j-1] + 1); 31 } 32 dp[i][j] = max(opt[i][j], max(dp[i-1][j], dp[i][j-1])); 33 } 34 } 35 36 printf("%d\n", dp[la][lb]); 37 } 38 return 0; 39 }