NOIP模拟73

T1:

  20分:状压DP或Dfs O(2^n)暴力

  60分:发现答案为1e5级别,做0/1背包即可

  100分:分析过程,由于要求最小的非幸运数,那么由于数的组成是连续的

  那么模拟过程发现,能够延伸所能组成的数的集合的单位数为:1,2,4,11,22,44

  进一步拓展发现第i个数为Pre[i - 1] + 1,因此若a[i] > Pre[i - 1] + 1,那么答案则为

  Pre[i - 1] + 1,时间复杂度O(nlogn)(sort排序)

代码如下:

 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 #define debug cout << "It's Ok Here !" << endl;
17 #define FP(x) freopen (#x,"r",stdin)
18 #define FC(x) freopen (#x,"w",stdout)
19 const I N = 1e5 + 3;
20 I n,a[N],Pre[N];
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 operator + (const P &a,const P &b) {
34     return MP (a.a + b.a,a.b + b.b);
35 }
36 inline P operator - (const P &a,const P &b) {
37     return MP (a.a - b.a,a.b - b.b);
38 }
39 
40 signed main () {
41     FP (math.in), FC (math.out);
42     n = read ();
43     for (I i(1);i <= n; ++ i) 
44         a[i] = read ();
45     sort (a + 1,a + n + 1);
46     for (I i(1);i <= n; ++ i)
47         Pre[i] = Pre[i - 1] + a[i];
48     for (I i(1);i <= n; ++ i)
49         if (a[i] > Pre[i - 1] + 1)
50             printf ("%lld\n",Pre[i - 1] + 1), exit (0);
51     printf ("%lld\n",Pre[n] + 1), exit (0);
52 }
View Code

T2:

  矩阵乘法,重新定义矩阵乘法为C[i][j] = $\prod$A[i][k]^B[k][j],于是直接调配矩阵系数即可

  需要注意的是,由于将幂乘转化为指数相加,那么在指数矩阵取模时需要根据费马定理对(mod - 1)取模

代码如下:

 1 %:pragma GCC optimize (2)
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 #define I long long
 5 #define C char
 6 #define B bool
 7 #define V void
 8 #define D double
 9 #define LL long long
10 #define UI unsigned int
11 #define UL unsigned long long
12 #define P pair<I,I>
13 #define MP make_pair
14 #define a first
15 #define b second
16 #define lowbit(x) (x & -x)
17 #define debug cout << "It's Ok Here !" << endl;
18 #define FP(x) freopen (#x,"r",stdin)
19 #define FC(x) freopen (#x,"w",stdout)
20 const I N = 200, mod = 998244353;
21 I n,t,F[N],G[N][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 operator + (const P &a,const P &b) {
35     return MP (a.a + b.a,a.b + b.b);
36 }
37 inline P operator - (const P &a,const P &b) {
38     return MP (a.a - b.a,a.b - b.b);
39 }
40 inline I fp (I a,I b) {
41     if (a == 0 || a == 1) return a;
42     I ans (1);
43     for (; b ;b >>= 1, a = a * a % mod)
44         if (b & 1) ans = ans * a % mod;
45     return ans;
46 }
47 inline V Matrix_mul () {
48     I X[N];
49     fill (X,X + t,1);
50     for (I k(0);k < t; ++ k)
51         for (I j(0);j < t; ++ j)
52             X[j] = X[j] * fp (F[k],G[k][j]) % mod;
53     memcpy (F,X,sizeof F);
54 }
55 inline V Matrix_self () {
56     I X[N][N];
57     memset (X,0,sizeof X);
58     for (I i(0);i < t; ++ i) 
59         for (I k(0);k < t; ++ k) if (G[i][k])
60             for (I j(0);j < t; ++ j) if (G[k][j])
61                 (X[i][j] += G[i][k] * G[k][j] % (mod - 1)) %= (mod - 1);
62     memcpy (G,X,sizeof X);
63 }
64 signed main () {
65     FP (seq.in), FC (seq.out);
66     n = read (), t = read ();
67     for (I i(0);i <  t; ++ i) 
68         G[i][0] = read ();
69     for (I i(0);i <  t; ++ i)
70         F[t - i - 1] = read ();
71     for (I i(0);i + 1 <  t; ++ i)
72         G[i][i + 1] = 1;
73     if (n <= t) printf ("%lld\n",F[t - n]), exit (0);
74     I x (n - t);
75     for (; x ;x >>= 1, Matrix_self ())
76         if (x & 1) Matrix_mul ();
77     printf ("%lld\n",F[0]);
78 }
View Code

T3:

  全源最短路,考虑在最短路过程中记录每个白点连向最短路的连边,最终在每个白点所有连边集合中取最小值即可

代码如下:

 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 LL long long
 8 #define UI unsigned int
 9 #define UL unsigned long long
10 #define P pair<I,I>
11 #define MP make_pair
12 #define a first
13 #define b second
14 #define lowbit(x) (x & -x)
15 #define debug cout << "It's Ok Here !" << endl;
16 #define FP(x) freopen (#x,"r",stdin)
17 #define FC(x) freopen (#x,"w",stdout)
18 const I N = 1e5 + 3;
19 B typ[N];
20 I n,m,d[N],pre[N],ans;
21 I tot,head[N],to[N << 2],nxt[N << 2],wgt[N << 2];   
22 vector <I> rec[N];
23 inline I read () {
24     I x(0),y(1); C z(getchar());
25     while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); }
26     while ( isdigit(z))  x = x * 10 + (z ^ 48), z = getchar();
27     return x * y;
28 }
29 inline V Max (I &a,I b) { a = a > b ? a : b; }
30 inline V Min (I &a,I b) { a = a < b ? a : b; }
31 inline I max (I a,I b) { return a > b ? a : b; }
32 inline I min (I a,I b) { return a < b ? a : b; }
33 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; }
34 inline I abs (I a) { return a >= 0 ? a : -a; }
35 inline P operator + (const P &a,const P &b) {
36     return MP (a.a + b.a,a.b + b.b);
37 }
38 inline P operator - (const P &a,const P &b) {
39     return MP (a.a - b.a,a.b - b.b);
40 }
41 inline V found (I z,I y,I x) {
42     to[++tot] = y, nxt[tot] = head[x], wgt[tot] = z, head[x] = tot;
43     to[++tot] = x, nxt[tot] = head[y], wgt[tot] = z, head[y] = tot;
44 }
45 inline V Dijkstra () {
46     priority_queue <P> q; B vis[N];
47     memset (vis,0,sizeof vis), memset (d,0x3f,sizeof d);
48     for (I i(1);i <= n; ++ i) if (typ[i])
49         q.push (MP (0,i)), d[i] = 0;
50     while (!q.empty ()) {
51         I x (q.top ().b); q.pop ();
52         if (vis[x]) continue; vis[x] = 1;
53         for (I i(head[x]),y(to[i]),z(wgt[i]); i ;i = nxt[i],y = to[i],z = wgt[i]) {
54             if (d[x] + z == d[y]) rec[y].push_back (z);
55             if (d[x] + z <  d[y]) d[y] = d[x] + z, q.push (MP (-d[y],y)), rec[y].clear (), rec[y].push_back (z);
56         }
57     }
58 }
59 signed main () {
60     FP (minimum.in), FC (minimum.out);
61     n = read (), m = read ();
62     for (I i(1);i <= n; ++ i)
63         typ[i] = read ();
64     for (I i(1);i <= m; ++ i) 
65         found (read (),read (),read ());
66     Dijkstra ();
67     for (I i(1);i <= n; ++ i) if (!typ[i]) {
68         if (rec[i].empty ()) puts ("impossible"), exit (0);
69         I MI (INT_MAX); for (auto x : rec[i]) Min (MI,x);
70         ans += MI;
71     }
72     printf ("%lld\n",ans);
73 }
View Code

T4:

  状压DP,是状态划分类型,考虑定义f[i]表示只考虑i集合中所有元素的拓扑序方案数

  那么对于(1 << j & i == 0)f[i | 1 << j] += f[i] * (1 << cnt),其中j为非i集合中的点,cnt为

  i集合中连向j点的边数,其意义为考虑将j点作为新集合的拓扑序最后一个,那么i集合对新集合

  的贡献即为f[i] * (1 << cnt),即任意删边

代码如下:

 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 #define debug cout << "It's Ok Here !" << endl;
17 #define FP(x) freopen (#x,"r",stdin)
18 #define FC(x) freopen (#x,"w",stdout)
19 const I N = 22, mod = 998244353;
20 I n,m,ans,f[1 << N],s[N];
21 I tot,head[N],to[N*N],nxt[N*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 operator + (const P &a,const P &b) {
35     return MP (a.a + b.a,a.b + b.b);
36 }
37 inline P operator - (const P &a,const P &b) {
38     return MP (a.a - b.a,a.b - b.b);
39 }
40 inline V found (I y,I x) {
41     to[++tot] = y, nxt[tot] = head[x], head[x] = y, s[y] |= 1 << x;
42 }
43 signed main () {
44     FP (topology.in), FC (topology.out);
45     n = read (), m = read ();
46     for (I i(1);i <= m; ++ i)
47         found (read () - 1, read () - 1);
48     f[0] = 1;
49     for (I i(0);i < 1 << n; ++ i) 
50         for (I j(0);j <  n; ++ j) if ((1 << j & i) == 0) {
51             I cnt (__builtin_popcount (s[j] & i));
52             (f[i | 1 << j] += f[i] * (1 << cnt) % mod) %= mod;
53         }
54     printf ("%lld\n",f[(1 << n) - 1]);
55 }
View Code

 附加题:奇妙的 Fibonacci

  结论题+积性筛模板:

  对于Fibonacci数列有:

  通项公式:

  证明:数学归纳法或者数列通项公式计算公式

  恒等式:

  

 

  证明:1~4通过fib定义式展开化简即可

     5:通过fib展开观察得到:

      f[n] = f[n - 1] + f[n - 2]

         = 2 * f[n - 2] + f[n - 3]

         = 3 * f[n - 3] + 2 * f[n - 4]

  数论性质:

  

 

  证明:首先证明fib相邻两项互质:

  比较简单的数学归纳法:(a,b) = 1 -> (a,a + b) = 1

  那么由上述恒等式5可得:证明式等价于:

  (f[m] * f[n - m + 1] + f[m - 1] * f[n - m],f[m]) = f[(n,m)]

  简单的数论化简得到(f[n - m],f[m]) = f[(n,m)]

  可以发现其为辗转相除形式,由于最终一定存在:

  (0,(a,b)) = (a,b),也就是(0,f[(n,m)]) = f[(n,m)] Q.E.D

  性质2:

  

 

  有了上述证明,本性质比较显然,考虑若f[n] | f[m]

  那么(f[n],f[m]) = f[n] = f[(n,m)],那么可以的得到:

  n = (n,m) -> n | m

  于是本题直接积性筛预处理即可

  (约数平方和积性函数证明:根据公式,对于每一项做平方即可)

火羽白日生的代码:

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 #define ull unsigned long long
 4 #define uint unsigned int
 5 #define rint register int
 6 #define int long long 
 7 using namespace std;
 8 namespace IO{
 9     #define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
10     #define debug puts("debug")
11     #define breakpoint exit(0)
12     #define out(x) cout<<#x<<" : "<<x<<"\n"
13     inline int read(){
14         int w=0,f=1; char ch=getchar();
15         while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
16         while(ch>='0'&&ch<='9'){w=(w<<3)+(w<<1)+(ch^48); ch=getchar();}
17         return w*f;
18     }
19     inline void write(int x,char ch='\n'){
20         static int sta[35]; int top=0;
21         if(x<0) putchar('-'),x=-x;
22         do{sta[++top]=x%10,x/=10;}while(x);
23         while(top) putchar(sta[top--]+48); putchar(ch);
24     }
25 }
26 using namespace IO;
27 namespace CL{
28     #define fill(x,y) memset(x,y,sizeof(x))
29     #define copy(x,y) memcpy(x,y,sizeof(y))
30 
31     const int maxn=1e7+5,mod=1e9+7;
32 
33     int q,qi,A,B,C,tot,ans1,ans2;
34     int prime[maxn],d[maxn],sqr[maxn],low[maxn];
35     bool is[maxn];
36     inline void init(int n){
37         fill(is,1);
38         d[1]=sqr[1]=1;
39         for(int i=2;i<=n;i++){
40             if(is[i]){
41                 prime[++tot]=i,low[i]=i,d[i]=2,sqr[i]=(i*i+1)%mod;
42                 for(int j=i*i;j<=n;j*=i) d[j]=d[j/i]+1,sqr[j]=(sqr[j/i]+j*j)%mod;
43             }
44             for(int j=1;j<=tot && i*prime[j]<=n;j++){
45                 is[i*prime[j]]=0;
46                 if(i%prime[j]==0){
47                     low[i*prime[j]]=low[i]*prime[j];
48                     if(low[i]!=i){
49                         d[i*prime[j]]=d[i/low[i]]*d[low[i]*prime[j]];
50                         sqr[i*prime[j]]=sqr[i/low[i]]*sqr[low[i]*prime[j]]%mod;
51                     }
52                     break;
53                 }
54                 low[i*prime[j]]=prime[j];
55                 d[i*prime[j]]=d[i]*d[prime[j]];
56                 sqr[i*prime[j]]=sqr[i]*sqr[prime[j]]%mod;
57             }
58         }
59     }
60 
61     inline int main(){
62         q=read(),qi=read(),A=read(),B=read(),C=read();
63         init(C);
64         while(q--){
65             ans1=(ans1+d[qi]+(qi&1))%mod;
66             ans2=(ans2+sqr[qi]+(qi&1)*4)%mod;
67             qi=(qi*A+B)%C+1;
68         }
69         printf("%lld\n%lld\n",ans1,ans2);
70         return 0;
71     }
72 }
73 signed main(){return CL::main();}
View Code

 附加题:中国象棋

  比较好的DP题

  考虑根据定义,同一行同一列不能同时存在三个炮,并且题目要求为计数

  那么计数题通常由于方案数极多并不能直接考虑每种方案,需要忽略一些信息

  来降低问题复杂度,对于本题而言,只需要考虑棋子的放置方案,对于棋子

  放置的具体位置并不关心,于是考虑设计f[i][j][k]表示只考虑前i行其中第i行

  有j列放置1个棋子,k列放置2个棋子,这样既保证转移的基本需要,有避开

  了棋子位置,转移时枚举上一次决策大力分类讨论即可,即不放棋子:直接继承

  放置一个棋子:考虑放置的位置,放置两个棋子:考虑分别放置在哪即可

代码如下:

 1 %: pragma GCC optimize(3)
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 #define I long long
 5 #define C char
 6 #define B bool
 7 #define V void
 8 #define D double
 9 #define LL long long
10 #define UI unsigned int
11 #define UL unsigned long long
12 #define P pair<I,I>
13 #define MP make_pair
14 #define a first
15 #define b second
16 #define lowbit(x) (x & -x)
17 #define debug cout << "It's Ok Here !" << endl;
18 #define FP(x) freopen (#x,"r",stdin)
19 #define FC(x) freopen (#x,"w",stdout)
20 const I N = 105, mod = 9999973;
21 I n,m,ans,f[N][N][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 operator + (const P &a,const P &b) {
35     return MP (a.a + b.a,a.b + b.b);
36 }
37 inline P operator - (const P &a,const P &b) {
38     return MP (a.a - b.a,a.b - b.b);
39 }
40 inline V Mod1 (I &a,I b) { a = a + b > mod ? a + b - mod : a + b; }
41 signed main () {
42     FP (chess.in), FC (chess.out);
43     n = read (), m = read ();
44     f[0][0][0] = 1;
45     for (I i(1);i <= n; ++ i) {
46         for (I j(0);j <= m; ++ j) {
47             for (I k(0);j + k <= m; ++ k) {
48                 f[i][j][k] = f[i - 1][j][k];
49                 if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1));
50                 if (j >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k] * (m - j + 1 - k));
51                 if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1] * (m - k + 1 - j) * j);
52                 if (k >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 2][k - 2] * (j + 2) * (j + 1) / 2);
53                 if (j >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 2][k] * (m - j + 2 - k) * (m - j + 1 - k) / 2);
54                 f[i][j][k] %= mod; if (i == n) Mod1 (ans,f[i][j][k]);
55             }
56         }
57     }
58     printf ("%lld\n",ans);
59 }
View Code

 

 

 

 


  

 

posted @ 2021-10-10 15:48  HZOI_LYM  阅读(39)  评论(0编辑  收藏  举报