正睿20NOIp前冲刺day2

估分:100+20+20+10=150

实际:0+20+0+0=20

T1:

  没注意只有两条入边,所以花了好多时间搞这玩意,最后还写炸了

  因为每个点只有两条入边和出边,所以把新建图,把出边相连,入边相连,答案就是2环数

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 200010;
 8 const int mod = 998244353;
 9 
10 int n;
11 int dout[N], din[N], fa[N], siz[N];
12 
13 int find1(int x)
14 {
15     return fa[x] == x ? x : fa[x] = find1(fa[x]);
16 }
17 
18 void add(int a, int b)
19 {
20     a = find1(a), b = find1(b);
21     if (siz[a] < siz[b]) swap(a, b);
22     fa[b] = fa[a];
23     siz[a] += siz[b];
24 }
25 
26 int main()
27 {
28     scanf("%d", &n);
29     for (int i = 1; i <= n * 2; i++) fa[i] = i, siz[i] = 1;
30     for (int i = 1; i <= n * 2; i++)
31     {
32         int a, b;
33         scanf("%d%d", &a, &b);
34         if (!dout[a]) dout[a] = i;
35         else add(i, dout[a]);
36         if (!din[b]) din[b] = i;
37         else add(i, din[b]);
38     }
39     int ans = 1;
40     for (int i = 1; i <= n * 2; i++)
41     {
42         if (find1(i) == i) ans = ans * 2 % mod;
43     }
44     printf("%d", ans);
45 }
View Code

 

T2:

  又是一个神仙DP,只写了20分全排列暴力

  因为p是一个排列,所以若有ai=i则一定无解。若有ai>i,我们就要把ai向右移动到ai处,当ai<i时向左移,所以我们就可以弄出若干个类似于p[i]<p[i-1]或p[i]>p[i-1]的限制,然后就能DP。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 5010;
 8 const int mod = 1e9 + 7;
 9 
10 int n;
11 int a[N], b[N];
12 int sum1[N], sum2[N];
13 int f[N][N];
14 
15 int main()
16 {
17     scanf("%d", &n);
18     for (int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i]++;
19     for (int i = 1; i <= n; i++)
20     {
21         if (a[i] == i)
22         {
23             puts("0");
24             return 0;
25         }
26     }
27 
28     for (int i = 1; i <= n; i++)
29     {
30         int l = i, r = a[i], k = 1;
31         if (l > r) swap(l, r), k = -1;
32         for (int j = l; j < r - 1; j++)
33         {
34             if (b[j] == -k)
35             {
36                 puts("0");
37                 return 0l;
38             }
39             b[j] = k;
40         }
41     }
42 
43     f[1][1] = 1;
44     for (int i = 2; i < n; i++)
45     {
46         for (int j = 1; j < i; j++) sum1[j] = (sum1[j - 1] + f[i - 1][j]) % mod;
47         for (int j = i - 1; j; j--) sum2[j] = (sum2[j + 1] + f[i - 1][j]) % mod;
48         for (int j = 1; j <= i; j++)
49         {
50             if (b[i - 1] == 1) f[i][j] = sum1[j - 1];
51             else f[i][j] = sum2[j];
52         }
53     }
54 
55     int ans = 0;
56     for (int i = 1; i < n; i++) ans = (ans + f[n - 1][i]) % mod;
57     printf("%d", ans);
58 }
View Code

 

T3:

  写了n=2的20分,但没开longlong

  找规律,就能找出这样的规律

  只需要把前两行和前两列变成0即可,如果此时还不能把整个矩阵归零那么必然无解。证明就考虑任意一个3*3的矩阵,a(1,1) − a(1,2) − a(2,1) + a(2,3) + a(3,2) − a(3,3) 的值在这些操作下永远不变。然后就能构造出来了,最多只需要4000步以下

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 #define pb push_back
 9 
10 typedef long long LL;
11 
12 const int N = 5010;
13 
14 int n, m;
15 LL t[N][N];
16 
17 struct Node
18 {
19     LL ex, id, v;
20     Node() {}
21     Node(LL ex, LL id, LL v) :ex(ex), id(id), v(v) {}
22 };
23 
24 vector<Node> ans;
25 
26 void add(int id, int k, LL x)
27 {
28     ans.pb(Node(id, k, x));
29     switch (id)
30     {
31     case 1:
32     {
33         for (int i = 1; i <= m; i++) t[k][i] += x;
34         break;
35     }
36     case 2:
37     {
38         for (int i = 1; i <= n; i++) t[i][k] += x;
39         break;
40     }
41     case 3:
42     {
43         for (int i = 1; i <= n; i++)
44         {
45             if (i + k <= m && i + k >= 1) t[i][i + k] += x;
46         }
47         break;
48     }
49     }
50 }
51 
52 int main()
53 {
54     scanf("%d%d", &n, &m);
55     for (int i = 1; i <= n; i++)
56     {
57         for (int j = 1; j <= m; j++)
58         {
59             scanf("%lld", &t[i][j]);
60         }
61     }
62 
63     for (int i = n; i >= 1; i--)
64     {
65         for (int j = 1; j <= 2; j++)
66         {
67             if (t[i][j]) j == 1 ? add(1, i, -t[i][j]) : add(3, j - i, -t[i][j]);
68         }
69     }
70 
71     for (int j = 1; j <= m; j++)
72     {
73         for (int i = 2; i >= 1; i--)
74         {
75             if (t[i][j]) i == 2 ? add(2, j, -t[i][j]) : add(3, j - i, -t[i][j]);
76         }
77     }
78 
79     for (int i = 1; i <= n; i++)
80     {
81         for (int j = 1; j <= m; j++)
82         {
83             if (t[i][j])
84             {
85                 puts("-1");
86                 return 0;
87             }
88         }
89     }
90 
91     printf("%d\n", ans.size());
92     for (auto i : ans) printf("%lld %lld %lld\n", i.ex, i.id, i.v);
93 }
View Code

 

T4:

  10分的暴力DP写炸了

  斜率优化DP,不会

 

总结:

  这次考得很不好,代码全炸,可能写得慌了,读题也是个问题,就因为第一题题目没读清楚浪费了好多时间,导致后面没时间对拍检验了。以后还是一题一题的来,在四个题之间反复横跳效果极其不好。

  

 

posted on 2020-10-13 17:12  ArrogHie  阅读(108)  评论(0编辑  收藏  举报