zoukankan      html  css  js  c++  java
  • 2018.10.05模拟总结

    今天的题自认为比Day1简单一些,而且出的质量很高(虽然数据有点水)。

     

    T1 a

      期望得分:30

      实际得分:30

      首先不得不吐槽一下:这题名字起的真糊弄。

      说下题吧,一拿到题发现O(n2)暴力就是送的,枚举起始点,再O(n)扫一遍。15分钟敲完后开始打表想想正解,发现对于一个数s[i],他对旋转k次的贡献有一部分是一个等差数列,而有一部分不是,准确说应该是分别有一个递增和递减,公差是1和-1的等差数列 ,以及单出来的一个1。于是我就想找规律,找了30多分钟硬是没找出来,不得不放弃写T2.

      T2,T3写完后又会来杠T1,总共用时1小时20分钟,还是只有暴力分……

      正解其实和我的思路比较像,但是他找到了等差数列的规律:s[i]对每一个答案的贡献可以分成三个等差数列,然后这道题就变成了区间加一个等差数列,最后求每一个数修改后的值。可以用线段树实现,不过更有的是二阶差分(详见这篇博客),总复杂度O(n)。

      但是规律比较复杂,没写出来。

      于是我们看第二种方法吧。

      强的过分的Dukelv用了不到40分钟AC了这道题,令人震惊。他跟我们说:就是暴力模拟啊!于是就有了一个O(n)暴力模拟的方法。

      对于每一次旋转,我们只用考虑旋转后相对于旋转前的答案变了什么,然后不断的维护当前的答案。

      因此我们需要一个big:记录当前有几个数s[i] >= i,以及sma:有几个数s[i] < i。然后每一次旋转,先考虑第一个数,因为他的移动方式和其他的都不一样:移到了最后,所以首先是big--, sma++,对答案的贡献少了s[i] - 1,多了n - s[i]。然后考虑剩下的数:有一些的答案由正变负,有一些有负变正。因此我们要开一个数组num[]记录当前有哪些数是负的(当然记录正的也行,反正一个就够了),num[x]表示 s[i] - i = -x的数有多少个,那也就是说,在第k次旋转后,num[k]的这些数就会有负变正,这样对于第 i 次旋转,big += num[i], sma -= num[i],于是对于big和sma的维护也完成了。

      有趣的是,标程的代码竟然和Dukelv一样,反而题解的做法没有代码。

    先发个30分吧

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e6 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38 #ifndef mrclr
    39     freopen("a.in", "r", stdin);
    40     freopen("a.out", "w", stdout);
    41 #endif    
    42 }
    43 
    44 int n, a[maxn];
    45 
    46 ll ans = INF;
    47 
    48 int main()
    49 {
    50     MYFILE();
    51     n = read();
    52     for(rg int i = 1; i <= n; ++i) a[i] = read();
    53     for(rg int i = 1; i <= n; ++i)
    54     {
    55         ll Min = 0;
    56         for(rg int j = i, k = 1; k <= n; ++k, ++j)
    57         {
    58             if(j > n) j -= n;
    59             Min += abs(a[j] - k);
    60             if(Min > ans) break;
    61         }
    62         ans = min(ans, Min);
    63     }
    64     write(ans); enter;
    65     return 0;
    66 }
    View Code

    满分的

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e6 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38     
    39 #ifndef mrclr
    40     freopen("a.in", "r", stdin);
    41     freopen("a.out", "w", stdout);
    42 #endif    
    43 }
    44 
    45 int n, a[maxn];
    46 int big = 0, sma = 0, num[maxn << 1];
    47 ll ans, Min = 0;
    48 
    49 int main()
    50 {
    51     MYFILE();
    52     n = read();
    53     for(int i = 1; i <= n; ++i)
    54     {
    55         a[i] = read();
    56         int x = a[i] - i;
    57         if(x >= 0) ++big, Min += x;
    58         else ++sma, Min -= x, num[-x]++;
    59     }
    60     ans = Min;
    61     for(int i = 1; i <= n; ++i)
    62     {
    63         int x = a[i] - 1, y = n - a[i];
    64         big--; Min -= x;
    65         sma++; Min += y; num[i + y]++;
    66         Min += big - sma + 1;
    67         if(num[i]) big += num[i], sma -= num[i];
    68         ans = min(ans, Min);
    69     }
    70     write(ans); enter;
    71     return 0;
    72 }
    View Code

    (都好短)

    T2 maze

      期望得分:30

      实际得分:10

      还是一眼秒30分,被卡掉20分是因为起点可能不合法,直接输出-1……出题人毒瘤的过分。

      正解我是无论如何也想不到的。看n特别小,觉得肯定要在这上面做文章,觉得可能是插头dp什么的,但最终还是没想出来。

      正解是咋回事儿呢:n这么小,那么我们就把他看成一个长度为m的序列吧!修改,查询用线段树维护就好啦~

      令人震惊。

      具体来说,就是对于一个区间[L, R],维护位于第L列所有的点到第R列所有的点的最短距离,也就是说,这个线段树上的每一个点是一个邻接矩阵,t[now].dis[i][j]表示a[i][L]到a[j][R]的最短距离!

      考虑修改:就是单点修改,然后暴力重构涉及到的每一个结点的矩阵。区间合并的时候,我们枚举左右子区间挨着的点,在枚举左子区间的起点和右子区间的终点,像floyd构造。

      查询:考虑起点和终点所在列不在同一区间的情况:其实和区间合并一样,floyd跑一遍,返回结构体。

      于是    写完了。感觉要是想到这个做法的话,这题就挺水的……

    30分bfs暴力

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxm = 2e5 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38     freopen("maze.in", "r", stdin);
    39 #ifndef mrclr
    40     freopen("maze.out", "w", stdout);
    41 #endif    
    42 }
    43 
    44 int n, m, q;
    45 bool a[6][maxm], vis[6][maxm];
    46 int sx, sy, ex, ey;
    47 const int dx[4] = {-1, 0, 1}, dy[4] = {0, 1, 0};
    48 struct Node
    49 {
    50     int x, y, dis;
    51 };
    52 void bfs()
    53 {
    54     if(!a[sx][sy] || !a[ex][ey] || ey < sy) {write(-1), enter; return;}
    55     for(int i = 1; i <= n; ++i)
    56         for(int j = sy - 1; j <= ey + 1; ++j) vis[i][j] = 0;
    57     queue<Node> q;
    58     q.push((Node){sx, sy, 0});
    59     vis[sx][sy] = 1;
    60     while(!q.empty())
    61     {
    62         Node now = q.front(); q.pop();
    63         if(now.x == ex && now.y == ey) {write(now.dis), enter; return;}
    64         for(int i = 0; i < 3; ++i)
    65         {
    66             int newx = now.x + dx[i], newy = now.y + dy[i];
    67             if(newx > 0 && newx <= n && newy > 0 && newy <= m && a[newx][newy] && !vis[newx][newy])
    68             {
    69                 vis[newx][newy] = 1;
    70                 q.push((Node){newx, newy, now.dis + 1});
    71             }
    72         }
    73     }
    74     write(-1), enter;
    75 }
    76 
    77 int main()
    78 {
    79     MYFILE();
    80     n = read(); m = read(); q = read();
    81     for(int i = 1; i <= n; ++i)
    82         for(int j = 1; j <= m; ++j) a[i][j] = (bool)read();
    83     for(int i = 1; i <= q; ++i)
    84     {
    85         int op = read();
    86         if(op == 1) 
    87         {
    88             int x = read(), y = read();
    89             a[x][y] ^= 1;
    90         }
    91         else
    92         {
    93             sx = read(), sy = read(), ex = read(), ey = read();
    94             bfs();
    95         }
    96     }
    97     return 0;
    98 }
    View Code

    正解

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxm = 2e5 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 void MYFILE()
     37 {
     38 #ifndef mrclr
     39     freopen("maze.in", "r", stdin);
     40     freopen("maze.out", "w", stdout);
     41 #endif    
     42 }
     43 
     44 int n, m, q, a[6][maxm];
     45 
     46 struct Tree
     47 {
     48     int l, r;
     49     int dis[6][6];
     50     Tree operator + (const Tree &oth)const
     51     {
     52         Tree ret;
     53         Mem(ret.dis, 0x3f);
     54         ret.l = l; ret.r = oth.r;
     55         for(int k = 1; k <= n; ++k) 
     56             for(int i = 1; i <= n; ++i)
     57                 for(int j = 1; j <= n; ++j)
     58                     ret.dis[i][j] = min(ret.dis[i][j], dis[i][k] + 1 + oth.dis[k][j]);
     59         return ret;
     60     }
     61 }t[maxm << 2];
     62 void build(int L, int R, int now)
     63 {
     64     t[now].l = L; t[now].r = R;
     65     if(L == R) 
     66     {
     67         Mem(t[now].dis, 0x3f);
     68         for(int i = 1; i <= n; ++i) 
     69             for(int j = i; j <= n; ++j) 
     70                 if(a[j][L]) t[now].dis[i][j] = t[now].dis[j][i] = j - i;
     71                 else break;
     72         return;
     73     }
     74     int mid = (L + R) >> 1;
     75     build(L, mid, now << 1);
     76     build(mid + 1, R, now << 1 | 1);
     77     t[now] = t[now << 1] + t[now << 1 | 1];
     78 }
     79 void update(int now, int d)
     80 {
     81     if(t[now].l == t[now].r) 
     82     {
     83         Mem(t[now].dis, 0x3f);
     84         for(int i = 1; i <= n; ++i) 
     85             for(int j = i; j <= n; ++j) 
     86                 if(a[j][t[now].l]) t[now].dis[i][j] = t[now].dis[j][i] = j - i;
     87                 else break;
     88         return;        
     89     }
     90     int mid = (t[now].l + t[now].r) >> 1;
     91     if(d <= mid) update(now << 1, d);
     92     else update(now << 1 | 1, d);
     93     t[now] = t[now << 1] + t[now << 1 | 1];
     94 }
     95 Tree query(int L, int R, int now)
     96 {
     97     if(L == t[now].l && R == t[now].r) return t[now];
     98     int mid = (t[now].l + t[now].r) >> 1;
     99     if(R <= mid) return query(L, R, now << 1);
    100     else if(L > mid) return query(L, R, now << 1 | 1);
    101     else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1);
    102 }
    103 
    104 int main()
    105 {
    106     MYFILE();
    107     n = read(); m = read(); q = read();
    108     for(int i = 1; i <= n; ++i)
    109         for(int j = 1; j <= m; ++j) a[i][j] = read();
    110     build(1, m, 1);
    111     for(int i = 1; i <= q; ++i)
    112     {
    113         int op = read();
    114         if(op == 1)
    115         {
    116             int x = read(), y = read();
    117             a[x][y] ^= 1; update(1, y);
    118         }
    119         else 
    120         {
    121             int sx = read(), sy = read(), ex = read(), ey = read();
    122             int ans = query(sy, ey, 1).dis[sx][ex];
    123             write(ans == INF ? -1 : ans); enter;
    124         }
    125     }
    126     return 0;
    127 }
    View Code

    T3 point

      期望得分:80~100

      实际得分:100

      这题我AC了!哈哈哈哈…………

      没错,我的方法就是正解。【得瑟】

      其实看到这题,我还是先想暴力:首先枚举区间长度len,然后枚举长度为len的所有区间,再对于每一个区间判断是否有价值:首先找区间最小值Min,然后找区间gcd,如果 Min | gcd (其实就是Min == gcd)的话就说明这个区间符合。加上求gcd的复杂度,O(n3logn)。

      然后我就想到,区间最小值和gcd可以用线段树实现,不用再O(nlogn)跑一遍,成功降到O(n2log2n)。

      然后想到st表预处理查询Min是O(1)的,gcd是O(logn)的,用st表吧,复杂度变成了O(n2logn)。

      最后想到枚举区间长度可以从大到小枚举,第一个符合的区间长度一定就是答案,但这样的话复杂度最坏还是能达到O(n2logn)。于是还是二分吧,稳定的O(logn)。于是最终的复杂度就是O(nlog2n)。

      总结一下:st表预处理区间最小值MIn和Gcd,复杂度O(nlog2n)。然后二分长度,O(nlogn)判断,复杂度还是O(nlog2n)。

    判断的时候加上break,最后再统计区间个数,把优化做到极致。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 5e5 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 void MYFILE()
     37 {
     38 #ifndef mrclr
     39     freopen("point.in", "r", stdin);
     40     freopen("point.out", "w", stdout);
     41 #endif    
     42 }
     43 
     44 int n;
     45 
     46 inline int gcd(int x, int y)
     47 {
     48     return y ? gcd(y, x % y) : x;
     49 }
     50 int dp[maxn][21][2], ha[maxn];
     51 void rmq()
     52 {
     53     for(rg int i = 1; i <= n; ++i) dp[i][0][0] = dp[i][0][1] = read();
     54     for(rg int j = 1; (1 << j) <= n; ++j)
     55         for(rg int i = 1; i + (1 << j) - 1 <= n; ++i)
     56         {
     57             dp[i][j][0] = min(dp[i][j - 1][0], dp[i + (1 << (j - 1))][j - 1][0]);
     58             dp[i][j][1] = gcd(dp[i][j - 1][1], dp[i + (1 << (j - 1))][j - 1][1]);
     59         }
     60     int x = 0;
     61     for(rg int i = 1; i <= n; ++i)
     62     {
     63         ha[i] = x;
     64         if((1 << (x + 1)) <= i + 1) x++;
     65     }
     66 }
     67 inline int query_Min(const int &L, const int &R)    //卡常…… 
     68 {
     69     int k = ha[R - L + 1];
     70     return min(dp[L][k][0], dp[R - (1 << k) + 1][k][0]);
     71 }
     72 inline int query_Gcd(const int &L, const int &R)
     73 {
     74     int k = ha[R - L + 1];
     75     return gcd(dp[L][k][1], dp[R - (1 << k) + 1][k][1]);
     76 }
     77 
     78 bool judge(const int &len)
     79 {
     80     for(rg int i = 1; i + len - 1 <= n; ++i)
     81     {
     82         int L = i, R = i + len - 1;
     83         int Min = query_Min(L, R), Gcd = query_Gcd(L, R);
     84         if(!(Gcd % Min)) return true;
     85     }
     86     return false;
     87 }
     88 
     89 int num = 0;
     90 vector<int> ans;
     91 
     92 int main()
     93 {
     94     MYFILE();
     95     n = read();
     96     rmq();
     97     int L = 0, R = n;
     98     while(L < R)
     99     {
    100         int mid = (L + R + 1) >> 1;
    101         if(judge(mid)) L = mid;
    102         else R = mid - 1;
    103     }
    104     for(rg int i = 1; i + L - 1 <= n; ++i)
    105     {
    106         int l = i, r = i + L - 1;
    107         int Min = query_Min(l, r), Gcd = query_Gcd(l, r);
    108         if(!(Gcd % Min)) num++, ans.push_back(i);
    109     }
    110     write(num); space; write(L - 1); enter;
    111     for(rg int i = 0; i < (int)ans.size(); ++i) write(ans[i]), space;
    112     enter;
    113     return 0;
    114 }
    View Code

    还特意写了个O(n3logn)对拍了一下,拍完4000组数据后安心了。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 5e5 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38     freopen("random.in", "r", stdin);
    39     freopen("bf.out", "w", stdout);
    40 }
    41 
    42 int gcd(int x, int y)
    43 {
    44     return y ? gcd(y, x % y) : x;
    45 }
    46 
    47 int n, a[maxn];
    48 int num = 0, val;
    49 vector<int> ans;
    50 
    51 int main()
    52 {
    53     MYFILE();
    54     n = read();
    55     for(int i = 1; i <= n; ++i) a[i] = read();
    56     for(int len = n; len >= 0; --len)
    57     {
    58         bool flg = 0;
    59         for(int i = 1; i + len - 1 <= n; ++i)
    60         {
    61             int L = i, R = i + len - 1;
    62             int Min = INF;
    63             for(int j = L; j <= R; ++j) Min = min(Min, a[j]);
    64             int Gcd = Min;
    65             for(int j = L; j <= R; ++j) Gcd = gcd(Gcd, a[j]);
    66             if(!(Gcd % Min)) 
    67             {
    68                 if(!flg) {ans.clear(); num = 0; val = len;}
    69                 flg = 1; num++;
    70                 ans.push_back(L);
    71             }
    72         }
    73         if(flg) break;
    74     }
    75     printf("%d %d
    ", num, val - 1);
    76     for(int i = 0; i < (int)ans.size(); ++i) write(ans[i]), space;
    77     enter;
    78     return 0;
    79 }
    View Code

    其实这次模拟挺闲的,T3 40多分钟就敲完了,剩下的时间T1,T2也没抠出来,硬是坐了一个多点……

  • 相关阅读:
    BZOJ.1028.[JSOI2007]麻将(贪心)
    BZOJ.1024.[SCOI2009]生日快乐(记忆化搜索)
    BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
    BZOJ.1026.[SCOI2009]windy数(数位DP)
    BZOJ.2125.最短路(仙人掌 最短路Dijkstra)
    BZOJ.1021.[SHOI2008]循环的债务(DP)
    BZOJ.1019.[SHOI2008]汉诺塔(递推)
    POJ.1379.Run Away(模拟退火)
    BZOJ.3680.吊打XXX(模拟退火/爬山算法)
    BZOJ.1018.[SHOI2008]堵塞的交通(线段树维护连通性)
  • 原文地址:https://www.cnblogs.com/mrclr/p/9745597.html
Copyright © 2011-2022 走看看