NOIP模拟62
T1:
没有想到是一道比较简单的鸽巢,关键点在于n个数并对n取模
考虑从特殊的模数n入手,于是可以发现,序列前缀和共有n种取值
当前缀和模n为0时显然直接输出即可,因此相当于n个数放入n-1个
抽屉种,显然必然会出现重复,因此一段连续区间中一定存在解
代码如下:
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<I,I> 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 const I N = 1e6 + 3; 18 I n,s,last[N]; 19 inline I read () { 20 I x(0),y(1); C z(getchar()); 21 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 22 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 23 return x * y; 24 } 25 inline V Max (I &a,I b) { a = a > b ? a : b; } 26 inline V Min (I &a,I b) { a = a < b ? a : b; } 27 inline I max (I a,I b) { return a > b ? a : b; } 28 inline I min (I a,I b) { return a < b ? a : b; } 29 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 30 inline I abs (I a) { return a >= 0 ? a : -a; } 31 inline P operator + (const P &a,const P &b) { 32 return MP (a.a + b.a,a.b + b.b); 33 } 34 inline P operator - (const P &a,const P &b) { 35 return MP (a.a - b.a,a.b - b.b); 36 } 37 signed main () { 38 n = read(); 39 for (I i(1);i <= n; ++ i) { 40 (s += read()) %= n; 41 if (s == 0) { 42 printf ("%d\n",i); 43 for (I j(1);j <= i; ++ j) 44 printf ("%d ",j); 45 exit (0); 46 } 47 if (last[s]) { 48 printf ("%d\n",i - last[s]); 49 for (I j(last[s] + 1);j <= i; ++ j) 50 printf ("%d ",j); 51 exit (0); 52 } 53 else last[s] = i; 54 } 55 puts ("-1"); 56 }
T2:
考场基本上想到正解,然而最后统计答案时直接输出cnt - 1
,显然的优化空间,考虑如何避开数组,与之前一道CF题的形式
相似,考虑当存在某一颜色长度大于n >> 1时显然无解,于是可以
利用栈模型,只需要尾指针判断是否存在该颜色,(仅判断是否
存在一种颜色大于n >> 1,并不需要具体颜色)在通过id记录颜色
最终再判断需要删几个即可
代码如下:
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<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It's Ok Here!" << endl; 17 #define log(x) ((I)log2(x)) 18 const I M = 1e3 + 3; 19 I m,k,color,cnt,W[M],X[M],Y[M],Z[M]; 20 inline LL read () { 21 LL x(0),y(1); C z(getchar()); 22 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 23 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 24 return x * y; 25 } 26 inline V Max (I &a,I b) { a = a > b ? a : b; } 27 inline V Min (I &a,I b) { a = a < b ? a : b; } 28 inline I max (I a,I b) { return a > b ? a : b; } 29 inline I min (I a,I b) { return a < b ? a : b; } 30 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 31 inline I abs (I a) { return a >= 0 ? a : -a; } 32 inline P operator + (const P &a,const P &b) { 33 return MP (a.a + b.a,a.b + b.b); 34 } 35 inline P operator - (const P &a,const P &b) { 36 return MP (a.a - b.a,a.b - b.b); 37 } 38 signed main () { 39 m = read(), k = read(); 40 for (I i(1);i <= m; ++ i) 41 W[i] = read(); 42 for (I i(1);i <= m; ++ i) 43 X[i] = read(); 44 for (I i(1);i <= m; ++ i) 45 Y[i] = read(); 46 for (I i(1);i <= m; ++ i) 47 Z[i] = read(); 48 I s ((1 << k) - 1); color = LONG_LONG_MIN; 49 for (I i(1);i <= m; ++ i) { 50 LL last (X[i]); 51 if (cnt && last != color) { 52 if (-- cnt == 0) cnt ++ , color = last; 53 } 54 else cnt ++ , color = last; 55 for (I j(1);j < W[i]; ++ j) { 56 last = (last * Y[i] + Z[i]) & s; 57 if (cnt && last != color) { 58 if (-- cnt == 0) cnt ++ , color = last; 59 } 60 else cnt ++ , color = last; 61 } 62 } 63 if (!cnt) { puts ("0"); exit (0); } 64 cnt = 0; I oth(0); 65 for (I i(1);i <= m; ++ i) { 66 LL last (X[i]); 67 last == color ? cnt ++ : oth ++ ; 68 for (I j(1);j < W[i]; ++ j) { 69 last = (last * Y[i] + Z[i]) & s; 70 last == color ? cnt ++ : oth ++ ; 71 } 72 } 73 printf ("%d\n",max (cnt - oth - 1,0ll)); 74 }
T3:
理解错题意,事实上当不考虑0边权时是一个比较简单的问题
若存在d(u,v) = d(u,k) + d(k,v)那么显然u,v边可以任意选择
考虑0边权的影响,显然为由于边权不增导致重复计算,于是
考虑如何计数,考虑当且仅当0边权形成一个个完全图时有解,否则
其内部的边最小值一定为0,并且若干完全图之间的边权一定相等
同理,于是首先考虑完全图之间的边,通过统计边权相同边数利用
简单容斥原理可以转化为不包含0边权的问题
考虑完全图内部的计数,于是直接根据问题设f[i]为存在i个点
的图的方案数,很容易想到容斥,对应的钦定j点为完全图,那么
剩余i-j个点任意选择,需要考虑两部分之间的边数为i * (n - i),由
于钦定,所以这部分贡献为k^(i * (n - i))(强制不选0),再计算
方案数为C(i - 1,j - 1),这里应用到的计数DP trick为在状态相互包
含时利用钦定点属于合法集来避免重复计算,因此为C(i - 1,j - 1)
代码如下:
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<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 const I N = 405, mod = 998244353; 17 I n,t,ans(1),d[N][N],J[N],Y[N],F[N],G[N]; 18 inline I read () { 19 I x(0),y(1); C z(getchar()); 20 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 21 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 22 return x * y; 23 } 24 inline V Max (I &a,I b) { a = a > b ? a : b; } 25 inline V Min (I &a,I b) { a = a < b ? a : b; } 26 inline I max (I a,I b) { return a > b ? a : b; } 27 inline I min (I a,I b) { return a < b ? a : b; } 28 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 29 inline I abs (I a) { return a >= 0 ? a : -a; } 30 inline P operator + (const P &a,const P &b) { 31 return MP (a.a + b.a,a.b + b.b); 32 } 33 inline P operator - (const P &a,const P &b) { 34 return MP (a.a - b.a,a.b - b.b); 35 } 36 inline I fp (I a,I b) { 37 I ans(1); 38 for (; b ;b >>= 1, a = a * a % mod) 39 if (b & 1) ans = ans * a % mod; 40 return ans; 41 } 42 inline I _C (I n,I m) { 43 if (!m || n == m) return 1; 44 return J[n] * Y[m] % mod * Y[n - m] % mod; 45 } 46 struct DJS { 47 I f[N],size[N]; 48 I get (I x) { 49 return x == f[x] ? x : f[x] = get (f[x]); 50 } 51 inline V merge (I x,I y) { 52 I fx (get (x)), fy (get (y)); 53 if (fx == fy) return ; 54 f[fy] = fx; size[fx] += size[fy]; 55 } 56 }DJS; 57 signed main () { 58 n = read(), t = read(); 59 for (I i(1);i <= n; ++ i) 60 DJS.f[i] = i, DJS.size[i] = 1; 61 for (I i(1);i <= n; ++ i) { 62 for (I j(1);j <= n; ++ j) 63 d[i][j] = read(); 64 if (d[i][i]) puts ("0"), exit (0); 65 } 66 for (I k(1);k <= n; ++ k) 67 for (I i(1);i <= n; ++ i) 68 for (I j(1);j <= n; ++ j) 69 if (d[i][k] + d[k][j] < d[i][j]) 70 puts ("0"), exit (0); 71 for (I i(1);i <= n; ++ i) 72 for (I j(1);j < i; ++ j) { 73 if (d[i][j] == 0) DJS.merge (i,j); 74 if (d[i][j] != d[j][i] || d[i][j] > t) 75 puts ("0"), exit (0); 76 } 77 J[0] = Y[0] = 1; 78 for (I i(1);i <= n; ++ i) 79 J[i] = J[i - 1] * i % mod; 80 Y[n] = fp (J[n],mod - 2); 81 for (I i(n - 1); i; -- i) 82 Y[i] = Y[i + 1] * (i + 1) % mod; 83 for (I i(1);i <= n; ++ i) { 84 F[i] = G[i] = fp (t + 1,i * (i - 1) >> 1); 85 for (I j(1);j < i; ++ j) { 86 (F[i] -= F[j] * G[i - j] % mod * _C (i - 1,j - 1) % mod * fp (t,j * (i - j) % mod)) %= mod; 87 if (DJS.f[i] != i || DJS.f[j] != j) continue; 88 B jud(0); 89 for (I k(1);k <= n; ++ k) { 90 I tmp (DJS.get (k)); 91 if (tmp != i && tmp != j && d[i][j] == d[i][tmp] + d[tmp][j]) { 92 jud = 1, ans = ans * fp (t - d[i][j] + 1,DJS.size[i] * DJS.size[j]) % mod; break; 93 } 94 } 95 if (!jud) ans = ans * (fp (t - d[i][j] + 1,DJS.size[i] * DJS.size[j]) - fp (t - d[i][j],DJS.size[i] * DJS.size[j])) % mod; 96 } 97 } 98 for (I i(1);i <= n; ++ i) if (DJS.f[i] == i) 99 ans = ans * F[DJS.size[i]] % mod; 100 printf ("%lld\n",(ans + mod) % mod); 101 }
T4:
直接口胡,比较容易发现转化题意可得实际是要求任意时刻
中位数需要小于等于剩余所有数,考虑首先O(n)遍历插入
维护中位数采用经典的对顶堆做法做到O(logn),考虑直观想法
是枚举剩余数判断插入该数后是否满足上述条件,然而时间复杂度跌至
O(n^2),考虑问题显然具有单调性,于是可以对序列排序后进行二分
然而发现线性结构删除元素基本在O(n),非线性结构又无法进行
二分,然而事实上O(n^2)的做法卡常可过