NOIP模拟64
T1:
考场上以为是数论题,想推性质,然而并不会,于是考虑60分
考虑发现数据范围中k <= 40,考虑模数很小,那么考虑计数问题的经典
解决方法——映射,考虑在1~k范围内求解,在反射回原值域,范围可以通过
不等式限制
正解并不是数论,而是数据结构维护,考虑类似排列,我们通过枚举
一维来解决限制,便于维护,通常以枚举中间量,可以限制出左右两侧变量
于是枚举b,发现一个很优秀的性质为a为一次,于是a + b^2的范围即可确定
,那么考虑c的贡献(即落到多少区间内),边更新边计算即可,树状数组
区间修改单点查询
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I long long 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define debug cout << "It's Ok Here !" << endl; 16 #define lowbit(x) (x & -x) 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I N = 1e5 + 3; 20 I T,n,t; 21 inline I read () { 22 I x(0),y(1); C z(getchar()); 23 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 24 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 25 return x * y; 26 } 27 inline V Max (I &a,I b) { a = a > b ? a : b; } 28 inline V Min (I &a,I b) { a = a < b ? a : b; } 29 inline I max (I a,I b) { return a > b ? a : b; } 30 inline I min (I a,I b) { return a < b ? a : b; } 31 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 32 inline I abs (I a) { return a >= 0 ? a : -a; } 33 inline P<I,I> operator + (const P<I,I> &a,const P<I,I> &b) { 34 return MP (a.a + b.a,a.b + b.b); 35 } 36 inline P<I,I> operator - (const P<I,I> &a,const P<I,I> &b) { 37 return MP (a.a - b.a,a.b - b.b); 38 } 39 struct BIT { 40 I c[N]; 41 inline V secmod (I x,I y) { 42 for (;x <= t;x += lowbit (x)) 43 c[x] ++ ; 44 for (;y <= t;y += lowbit (y)) 45 c[y] -- ; 46 } 47 inline I preque (I x) { I ans(0); 48 for (; x ;x -= lowbit (x)) 49 ans += c[x]; 50 return ans; 51 } 52 }B1; 53 signed main () { 54 FP (exclaim.in), FC (exclaim.out); 55 T = read(); 56 for (I i(1);i <= T; ++ i) { 57 printf ("Case %d: ",i); 58 n = read(), t = read(); I tmp(0); LL ans(0); 59 for (I j(1);j <= n; ++ j) { 60 I l((j * j + 1) % t + 1), 61 r((j * j + j) % t + 1); 62 if (j >= t) tmp += j / t - (r + 1 == l) - (r - l + 1 == t); 63 if (l <= r) B1.secmod (l,r + 1); 64 if (l > r) B1.secmod (1,r + 1), B1.secmod (l,t + 1); 65 I last (ans); 66 ans += tmp + B1.preque (j * j * j % t + 1); 67 } 68 printf ("%lld\n",ans); 69 memset (B1.c,0,sizeof B1.c); 70 } 71 }
T2:
首先看错题目暴毙,要求循环同构,于是首先简单的想法为n^2枚举区间
那么考虑如何O(1)判断循环同构,字符串匹配一种常见的方法显然为哈希
然而并不能应对循环,考虑剪枝,这里应用到字符集优化,即通过字符集哈希
首先判断两端字符是否相等,在进行循环判断,可以通过此题,再通过map记录
可以应对Hack数据
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define debug cout << "It's Ok Here !" << endl; 16 #define lowbit(x) (x & -x) 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I N = 5e3 + 3; 20 I n,ans; 21 UL p[N],f[N],t[N]; 22 inline I read () { 23 I x(0),y(1); C z(getchar()); 24 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 25 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 26 return x * y; 27 } 28 inline V Max (I &a,I b) { a = a > b ? a : b; } 29 inline V Min (I &a,I b) { a = a < b ? a : b; } 30 inline I max (I a,I b) { return a > b ? a : b; } 31 inline I min (I a,I b) { return a < b ? a : b; } 32 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 33 inline I abs (I a) { return a >= 0 ? a : -a; } 34 inline P<I,I> operator + (const P<I,I> &a,const P<I,I> &b) { 35 return MP (a.a + b.a,a.b + b.b); 36 } 37 inline P<I,I> operator - (const P<I,I> &a,const P<I,I> &b) { 38 return MP (a.a - b.a,a.b - b.b); 39 } 40 inline B Check (I l,I r) { 41 I mid (l + r >> 1), len (r - l + 1 >> 1); 42 if (t[r] - t[mid] != t[mid] - t[l - 1]) return false; 43 UL com (f[r] - f[mid] * p[len]); 44 for (I i(l);i <= mid; ++ i) 45 if ((f[mid] - f[i] * p[mid - i] - f[l - 1]) * p[i - l + 1] + f[i] == com) 46 return true; 47 return false; 48 } 49 signed main () { 50 FP (s.in), FC (s.out); 51 n = read(); p[0] = 1; 52 for (I i(1);i <= 5000; ++ i) 53 p[i] = p[i - 1] * 13331; 54 for (I i(1),x,y;i <= n; ++ i) { 55 x = read(); 56 t[i] = t[i - 1] + p[x]; 57 f[i] = f[i - 1] * 13331 + x; 58 if (x == y) ans ++ ; y = x; 59 } 60 for (I len(3);len < n;len += 2) 61 for (I i(1);i + len <= n; ++ i) { 62 if (Check (i,i + len)) ans ++ ; 63 } 64 printf ("%d\n",ans); 65 }
T3:
有向图求路径数,比较经典的矩阵乘法问题,分析矩阵乘法的性质我们可以发现
其可以视作图上路径问题,例如A[i][j] += A[i][k] * A[k][j],即从i到j的路径方案数=i-k * k-j
于是考虑在矩阵视角分析此题,于是环就等价于主对角线上的位置,那么问题就等价于
求sigma (A^1 + A^2 + ... + A^(k - 1))主对角线上的值,等比数列显然可以分治解决
然而时间复杂度O(n^3log^2n),并不太能过,于是发现可以直接预处理同底数幂降低时间复杂度
其实分析时间复杂度瓶颈很容易发现预处理解决的方法
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define V void 6 #define FP(x) freopen (#x,"r",stdin) 7 #define FC(x) freopen (#x,"w",stdout) 8 #define N 100 9 I n,k,mod,ans; 10 C s[N]; 11 inline I Mod (I a) {return a > mod ? a - mod : a;} 12 struct MAT { 13 I A[N][N]; MAT () { memset (A,0,sizeof A); } 14 }A,Pre[20]; 15 inline I read () { 16 I x(0); C z(getchar()); 17 while (!isdigit(z)) z = getchar(); 18 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 19 return x; 20 } 21 inline V print (MAT A) { 22 for (I i(0);i < n; ++ i) { 23 for (I j(0);j < n; ++ j) 24 cout << A.A[i][j] << ' '; 25 cout << endl; 26 } 27 cout << endl; 28 } 29 inline MAT operator * (const MAT &X,const MAT &Y) { 30 MAT Z; 31 for (I i(0);i < n; ++ i) 32 for (I k(0);k < n; ++ k) 33 for (I j(0);j < n; ++ j) 34 Z.A[i][j] = Mod (Z.A[i][j] + 1ll * X.A[i][k] * Y.A[k][j] % mod); 35 return Z; 36 } 37 inline MAT operator ^ (MAT X,I t) { 38 MAT Z; 39 for (I i(0);i < n; ++ i) 40 Z.A[i][i] = 1; 41 for (I i(0); t ;t >>= 1, ++ i) 42 if (t & 1) Z = Z * Pre[i]; 43 return Z; 44 } 45 inline MAT operator + (const MAT &X,const MAT &Y) { 46 MAT Z; 47 for (I i(0);i < n; ++ i) 48 for (I j(0);j < n; ++ j) 49 Z.A[i][j] = Mod (X.A[i][j] + Y.A[i][j]); 50 return Z; 51 } 52 MAT Divide (I x) { 53 I mid (x >> 1); MAT F (mid == 1 ? A : Divide (mid)); 54 return x & 1 ? ((A ^ mid) * F) + F + (A ^ x) : ((A ^ mid) * F) + F; 55 } 56 signed main () { 57 FP (tour.in), FC (tour.out); 58 n = read(); 59 for (I i(0);i < n; ++ i) { 60 scanf ("%s",s); 61 for (I j(0);j < n; ++ j) 62 A.A[i][j] = s[j] == 'Y'; 63 } 64 k = read(), mod = read(); 65 Pre[0] = A; 66 for (I i(1);i < 20; ++ i) 67 Pre[i] = Pre[i - 1] * Pre[i - 1]; 68 MAT F (Divide (k - 1)); 69 for (I i(0);i < n; ++ i) 70 ans = Mod (ans + F.A[i][i]); 71 printf ("%d\n",ans); 72 }