2019.9.14校内考试

T1:

   发现正方形棋盘,其边长为2k(1<k<10),而且2k(1<k<10)-1能被3整除,就想到了分治(主要还是qbzt的老师讲过)。每次将大棋盘从中间分成4个正方形的小棋盘,根据坏点在第几个棋盘分类处理,最后在棋盘大小分为2的时候就可以结束递归了。

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 
 4 using namespace std;
 5 
 6 int a,map[514][514],len[10]={1,2,4,8,16,32,64,128,256,512},k,ex,ey;
 7 
 8 void erfen(int zx,int zy,int yx,int yy,int hx,int hy)
 9 {
10     int zhongx=(zx+yx)>>1,zhongy=(zy+yy)>>1;
11     if(zhongx==zx&&zhongy==zy)//最后要终止递归时在分类把小棋盘剩下的未确认数的点填一下 
12     {
13         if(zx==hx&&zy==hy)
14         {
15             map[zx+1][zy]=map[zx+1][zy+1]=map[zx][zy+1]=4;
16         }
17         if(zx==hx&&zy+1==hy)
18         {
19             map[zx][zy]=map[zx+1][zy]=map[zx+1][zy+1]=3;
20         }
21         if(zx+1==hx&&zy==hy)
22         {
23             map[zx][zy]=map[zx][zy+1]=map[zx+1][zy+1]=2;
24         }
25         if(zx+1==hx&&zy+1==hy)
26         {
27             map[zx][zy]=map[zx+1][zy]=map[zx][zy+1]=1;
28         }
29         return;
30     }
31     if(hx<=zhongx&&hy<=zhongy)//已经确定数的点在左上
32     {
33         map[zhongx+1][zhongy+1]=map[zhongx+1][zhongy]=map[zhongx][zhongy+1]=4;
34         erfen(zx,zy,zhongx,zhongy,hx,hy);
35         erfen(zhongx+1,zy,yx,zhongy,zhongx+1,zhongy);
36         erfen(zx,zhongy+1,zhongx,yy,zhongx,zhongy+1);
37         erfen(zhongx+1,zhongy+1,yx,yy,zhongx+1,zhongy+1);
38     }
39     if(hx>zhongx&&hy<=zhongy)//已经确定数的点在左下 
40     {
41         map[zhongx+1][zhongy+1]=map[zhongx][zhongy]=map[zhongx][zhongy+1]=2;
42         erfen(zx,zy,zhongx,zhongy,zhongx,zhongy);
43         erfen(zhongx+1,zy,yx,zhongy,hx,hy);
44         erfen(zx,zhongy+1,zhongx,yy,zhongx,zhongy+1);
45         erfen(zhongx+1,zhongy+1,yx,yy,zhongx+1,zhongy+1);
46     }
47     if(hx<=zhongx&&hy>zhongy)//在右上 
48     {
49         map[zhongx+1][zhongy+1]=map[zhongx][zhongy]=map[zhongx+1][zhongy]=3;
50         erfen(zx,zy,zhongx,zhongy,zhongx,zhongy);
51         erfen(zhongx+1,zy,yx,zhongy,zhongx+1,zhongy);
52         erfen(zx,zhongy+1,zhongx,yy,hx,hy);
53         erfen(zhongx+1,zhongy+1,yx,yy,zhongx+1,zhongy+1);
54     }
55     if(hx>zhongx&&hy>zhongy)//在右下 
56     {
57         map[zhongx][zhongy+1]=map[zhongx][zhongy]=map[zhongx+1][zhongy]=1;
58         erfen(zx,zy,zhongx,zhongy,zhongx,zhongy);
59         erfen(zhongx+1,zy,yx,zhongy,zhongx+1,zhongy);
60         erfen(zx,zhongy+1,zhongx,yy,zhongx,zhongy+1);
61         erfen(zhongx+1,zhongy+1,yx,yy,hx,hy);
62     }
63 }
64 
65 void print()//输出矩阵 
66 {
67     for(int i=1;i<=a;i++)
68     {
69         for(int j=1;j<a;j++)
70             putchar(map[i][j]+'0'),putchar(' ');
71         putchar(map[i][a]+'0'),putchar('
');
72     }
73 }
74 
75 int main()
76 {
77     freopen("chessboard.in","r",stdin);
78     freopen("chessboard.out","w",stdout);
79     cin>>k>>ey>>ex;
80     a=len[k];
81     map[ex][ey]=7;
82     erfen(1,1,a,a,ex,ey);
83     print();
84     return 0;
85 } 
View Code

T2:

   将前n-1条边与n个点组成的树建出来,用线段树维护在DFS序的一段区间的所有点中从根节点到某个点的路径长度加上这个点向上到根节点的路径长度之和的最小值。修改后n-1条边中的边为单点修改(只影响一个点回到根节点的路径长度),修改前n-1条边中的边为区间修改(影响从根节点到到 以该边终点为根的子树中所有点的路径的长度)。查询也分两种情况:y在x的子树中、y不在x的子树中。细节什么的看代码(by _rqy)吧:

  1 #include <cstdio>
  2 #include <cctype>
  3 #include <vector>
  4 #define ll long long
  5 #include <algorithm>
  6 const ll maxn = 200005;
  7 const ll inf = 1e13;
  8 struct edge{
  9     ll from, to, w;
 10     edge(ll c, ll a, ll b):from(c), to(a),w(b){}
 11     edge(){}
 12 }e[maxn << 1];//存所有边(因为修改边时得看边的编号) 
 13 ll n, q, cnt, dfn, ans;
 14 ll fa[maxn][20];
 15 ll f[maxn], dep[maxn], deep[maxn], l[maxn], que[maxn], r[maxn];
 16 //dep(对应结构体里的dat)从根节点走到某个点的路径的长度
 17 //f 从某个点向上走到根节点的路径的长度==这个点连向根节点的边的长度 
 18 std::vector<ll> to[maxn];//树中的边 
 19 void add_edge(ll u, ll v, ll w) {
 20     e[++cnt] = edge(u, v, w); 
 21     to[u].push_back(cnt);
 22 }
 23 ll read() {
 24     ll x = 0, f = 1;
 25     char ch = getchar();
 26     while(!isdigit(ch)) {
 27     if(ch == '-') f = -1;
 28     ch = getchar();
 29     }
 30     while(isdigit(ch)) {
 31     x = x * 10 + ch - '0';
 32     ch = getchar();
 33     }
 34     return x * f;
 35 }
 36 struct seg{
 37     ll l, r, min, dat, tag1, tag2; //tag1:dep, tag2:f
 38 }t[maxn<<2];//线段树 
 39 void update(ll k) {
 40     t[k].min = std::min(t[k<<1].min, t[k<<1|1].min);
 41 }
 42 void pushdown(ll k) {
 43     if(t[k].l == t[k].r) return;
 44     if(t[k << 1].l == t[k<<1].r) t[k<<1].dat += t[k].tag1;
 45     if(t[k << 1|1].l == t[k<<1|1].r)t[k<<1|1].dat += t[k].tag1;
 46     t[k<<1].min += t[k].tag2 + t[k].tag1;
 47     t[k<<1|1].min += t[k].tag2 + t[k].tag1;
 48     t[k<<1].tag1 += t[k].tag1;
 49     t[k<<1].tag2 += t[k].tag2;
 50     t[k<<1|1].tag1 += t[k].tag1;
 51     t[k<<1|1].tag2 += t[k].tag2;
 52     t[k].tag1 = t[k].tag2 = 0;
 53 }
 54 void build(ll k, ll l, ll r) {//建线段树 
 55     t[k].l = l, t[k].r = r, t[k].tag1 = t[k].tag2 = 0;
 56     if(l == r) {
 57     t[k].min = dep[que[l]] + f[que[l]];
 58     t[k].dat = dep[que[l]];
 59     return;
 60     }
 61     ll mid = (l + r) >> 1;
 62     build(k << 1, l, mid);
 63     build(k << 1|1, mid+1, r);
 64     update(k);
 65 }
 66 void modify(ll k, ll x, ll y, ll a, ll arg = 0) {
 67     pushdown(k);
 68     ll l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
 69     if(x <= l && r <= y) {
 70     if(arg == 0) {//区间修改 
 71         t[k].tag1 += a; //tag1:由dat(或dep,毕竟dat和dep都一个意思)的变化而打的标记 
 72         t[k].min += a;
 73         if(t[k].l == t[k].r) t[k].dat += a;
 74     }
 75     else {//单点修改 
 76         t[k].tag2 += a;//tag2:由f的变化而打的标记 
 77         t[k].min += a;
 78     }
 79     return;
 80     }
 81     if(x <= mid) modify(k << 1, x, y, a, arg);
 82     if(y > mid) modify(k << 1|1, x, y, a, arg);
 83     update(k);
 84 }
 85 ll pos(ll k, ll p) {
 86     pushdown(k);
 87     ll l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
 88     if(l == r) return t[k].dat;
 89     if(p <= mid) return pos(k << 1, p);
 90     else return pos(k << 1|1, p);
 91 }
 92 ll query(ll k, ll x, ll y) {
 93     pushdown(k);
 94     ll l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
 95     if(x <= l && r <= y) return t[k].min;
 96     ll ans = inf;
 97     if(x <= mid) ans = std::min(ans, query(k << 1, x, y));
 98     if(y > mid) ans = std::min(ans, query(k << 1|1, x, y));
 99     return ans;
100 }
101 void dfs(ll x, ll fa) {
102     l[x] = ++dfn;
103     que[dfn] = x;
104     for(ll i = 0; i < to[x].size(); i++) {
105     ll v = e[to[x][i]].to;
106     if(v != fa) {
107         dep[v] = dep[x] + e[to[x][i]].w;
108         deep[v] = deep[x] + 1;
109         dfs(v, x);
110     }
111     }
112     r[x] = dfn;
113 }
114 void pre() {
115     scanf("%lld %lld", &n, &q);
116     for(ll i = 1; i < n; i++) {
117     ll u = read(), v = read();
118     add_edge(u, v, read());
119     fa[v][0] = u;
120     }
121     for(ll i = 1; i < n; i++) {
122     ll u = read(), v = read();
123     f[u] = read();
124     e[++cnt] = edge(u, v, f[u]);
125     }
126     for(ll i = 1; i <= 18; i++)
127     for(ll j = 1; j <= n; j++)
128         fa[j][i] = fa[fa[j][i-1]][i-1];
129     dfs(1, 0);
130     build(1, 1, dfn);
131 }
132 ll get(ll x, ll d) {
133     ll D = deep[x];
134     ll p = D - d;
135     if(p < 0) return -1;
136     ll u = x;
137     for(ll i = 18; i >= 0 && p; i--) {
138     if((1<<i) <= p) {
139         p -= (1<<i);
140         u = fa[u][i];
141     }
142     }
143     return u;
144 }
145 void solve() {
146     while(q--) {
147     ll k = read(), x = read(), y = read();
148     if(k == 2) {
149         if(x > (n-1)) {
150         modify(1, l[e[x].from], l[e[x].from], y - f[e[x].from], 1);
151         f[e[x].from] = y;
152         }
153         else {
154         ll delta = y - e[x].w;
155         ll u = e[x].to;
156         modify(1, l[u], r[u], delta);
157         e[x].w = y;
158         }
159     }
160     else {
161         ll k = get(y, deep[x]);
162         if(k == x) ans = pos(1, l[y]) - pos(1, l[x]);
163         else ans = query(1, l[x], r[x]) - pos(1, l[x]) + pos(1, l[y]);
164         printf("%lld
", ans);
165     }
166     }
167 }
168 int main() {
169 #ifdef orz
170     freopen("input", "r", stdin);
171 #endif
172     pre();
173     solve();
174 }
View Code

T3:

   子任务1就是kmp裸题,没什么好说的。

   子任务2用一遍kmp优化一下加暴力就过了,也没什么好说的(主要还是数据水)。

      正解看不懂。。。

   子任务3用卷积(下标和为常数),没什么会说的。。。

  还是把会的说说吧:

  1、两个多项式相乘得出x次项的系数为sigma(ai*bj)    i+j==x,x为常数, 这就是个卷积。多项式可以用系数表示,也可以用点表示。n个点可以表示出一个n-1次的多项式。对于两个多项式(设次数分别为i、j)f(x)和g(x)相乘,可以各取(次数和加1)对对应点,每对对应点的横坐标都应相同,这样两个多项式相乘得出新的多项式f(x)g(x)在坐标系中的体现即为每对对应点的纵坐标相乘得出一个新的点,共得出i+j-1个新点,将这些新点在转化为系数表示法即可得到f(x)g(x)。尽管用拉格朗日差值公式来做时O(n2)的时间复杂度(同暴力),但运用FFT(快速傅里叶变换)只需O(n log n)的复杂度,故我们有了一个更快的求多项式相乘结果的方法(注:FFT设及到复数实数乘法,要注意精度带来的问题),同时也可利用多项式乘法求下卷积。

  2、子任务3的部分思路:设模式串为A,主串为B,C(i,j)=(Ai-Bj)2,若Ai==Bj,则C(i,j)==0。若C(k,0)+...+C(i,j)==0,就说明有一段匹配成功。为了快速求和,可以搞成卷积的形式(要有乘法两乘数下标为常数)。怎么办呢?两个字符串都反过来看原来的位置就好了。字符串还有'?',怎么办?让‘?’=0,给每个C(i,j)再乘上Ai*Bi就好了,照样能搞卷积。最后将两串用FFT乘一下,系数为零的项的次数搞搞就是一个位置了。

见正解代码(by _rqy):

  1 #include <algorithm>
  2 #include <cmath>
  3 #include <complex>
  4 #include <cstdio>
  5 #include <cstring>
  6 typedef long long LL;
  7 const int N = 1000000;
  8 char s[N], p[N];
  9 int n, m;
 10 int something[N];
 11 namespace Task1{
 12   int* const nxt = something;
 13   void getNxt() {
 14     nxt[0] = nxt[1] = 0;
 15     for (int i = 1, j = 0; i < m; ++i) {
 16       while (j && p[i] != p[j]) j = nxt[j];
 17       nxt[i + 1] = (p[i] == p[j] ? ++j : 0);
 18     }
 19   }
 20   void solve() {
 21     int ans1 = 0, ans2 = 0;
 22     getNxt();
 23     for (int i = 0, j = 0; i < n; ++i) {
 24       while (j && p[j] != s[i]) j = nxt[j];
 25       if (p[j] == s[i] && (++j == m)) {
 26         ++ans1;
 27         ans2 ^= i - m + 1;
 28       }
 29     }
 30     printf("%d %d
", ans1, ans2);
 31   }
 32 };
 33 namespace Task2{
 34   int *const f = something;
 35   void getF() {
 36     f[0] = m;
 37     int rmax = 0, ri = 0;
 38     for (int i = 1; i < m; ++i) {
 39       f[i] = std::max(0, std::min(f[i - ri], rmax - i));
 40       while (p[f[i]] == p[i + f[i]]) ++f[i];
 41       if (i + f[i] > rmax)
 42         rmax = i + f[ri = i];
 43     }
 44   }
 45   void solve() {
 46     int ansv[4] = {0, 0, 0, 0};
 47     getF();
 48     int rmax = 0, ri = 0;
 49     for (int i = 0; i < n; ++i) {
 50       int ans = std::max(0, std::min(rmax - i, f[i - ri]));
 51       while (i + ans < n && ans < m && s[i + ans] == p[ans]) ++ans;
 52       if (i + ans > rmax)
 53         rmax = (ri = i) + ans;
 54       ansv[i % 4] ^= ans;
 55     }
 56     printf("%d %d %d %d
", ansv[0], ansv[1], ansv[2], ansv[3]);
 57   }
 58 };
 59 namespace Task3{
 60   const int N = 400000;
 61   typedef std::complex<double> Complex;
 62   const double pi = acos(-1.0);
 63   Complex PA[N], PB[N];
 64   LL A[N], B[N], C[N];
 65   void FFT(Complex *P, int len, int opt) {
 66     for (int i = 1, j = len >> 1, k; i < len; ++i) {
 67       if (i < j) std::swap(P[i], P[j]);
 68       k = len;
 69       do j ^= (k >>= 1); while (~j & k);
 70     }
 71     for (int h = 2; h <= len; h <<= 1) {
 72       Complex wn = Complex(cos(2 * pi * opt / h), sin(2 * pi * opt / h));
 73       for (int j = 0; j < len; j += h) {
 74         Complex w = Complex(1.0, .0);
 75         for (int k = 0; k < h / 2; ++k) {
 76           Complex tmp = P[j + k], tmp2 = P[j + k + h / 2] * w;
 77           P[j + k] = tmp + tmp2;
 78           P[j + k + h / 2] = tmp - tmp2;
 79           w *= wn;
 80         }
 81       }
 82     }
 83     if (opt == -1) {
 84       for (int i = 0; i < len; ++i)
 85         P[i] /= len;
 86     }
 87   }
 88   void upd(LL *A, LL *B, LL *C, int n, int m) { //A += B[0..n-1] * C[0..m-1]
 89     int len = 1;
 90     while (len < n + m) len <<= 1;
 91     for (int i = 0; i < n; ++i) PA[i] = B[i];
 92     for (int i = n; i < len; ++i) PA[i] = .0;
 93     for (int i = 0; i < m; ++i) PB[i] = C[i];
 94     for (int i = m; i < len; ++i) PB[i] = .0;
 95     FFT(PA, len, 1);
 96     FFT(PB, len, 1);
 97     for (int i = 0; i < len; ++i)
 98       PA[i] *= PB[i];
 99     FFT(PA, len, -1);
100     for (int i = 0; i < len; ++i)
101       A[i] += (LL)(PA[i].real() + (PA[i].real() > 0 ? 0.5 : -0.5));
102   }
103   inline LL sqr(LL x) { return x * x; }
104   inline LL cube(LL x) { return x * x * x; }
105   void solve() {
106     for (int i = 0; i < n; ++i)
107       B[i] = sqr(s[i] - 'a' + 1);
108     for (int i = 0; i < m; ++i)
109       C[i] = (p[m - i - 1] == '?' ? 0 : p[m - i - 1] - 'a' + 1);
110     upd(A, B, C, n, m);
111     for (int i = 0; i < n; ++i)
112       B[i] = -2 * (s[i] - 'a' + 1);
113     for (int i = 0; i < m; ++i)
114       C[i] = sqr(C[i]);
115     upd(A, B, C, n, m);
116     LL t = 0;
117     for (int i = 0; i < m; ++i) if (p[i] != '?')
118       t += cube(p[i] - 'a' + 1);
119     int ans1 = 0, ans2 = 0;
120     for (int i = 0; i <= n - m; ++i) if (A[i + m - 1] == -t) {
121       ++ans1;
122       ans2 ^= i;
123     }
124     printf("%d %d
", ans1, ans2);
125   }
126 }
127 int main() {
128   int task;
129   scanf("%d%s%s", &task, s, p);
130   n = strlen(s);
131   m = strlen(p);
132   if (task == 1) Task1::solve();
133   if (task == 2) Task2::solve();
134   if (task == 3) Task3::solve();
135   return 0;
136 }
View Code
原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/11523384.html