zoukankan      html  css  js  c++  java
  • 2017年浙江省赛总结

      最终是5题银。其实感觉再给点时间能7题的,主要是最后机子不够用了,没时间调试了,当然代码能力弱也是很大的一个问题。

      E题,队友当时卡了很久,最终是A了。赛后发现就是一个很水的数位DP。。代码如下:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 using namespace std;
     5 typedef long long ll;
     6 
     7 int T,n;
     8 char s[15];
     9 int bit[15];
    10 ll dp[15][200];
    11 int val[] = {6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
    12 int get(char c)
    13 {
    14     if(c <= '9') return c - '0';
    15     return c - 'A' + 10;
    16 }
    17 ll dfs(int pos,int sum,bool flag)
    18 {
    19     if(pos == -1) return sum;
    20     ll& ans = dp[pos][sum];
    21     if(flag && ans!=-1) return ans;
    22     int d = flag?15:bit[pos];
    23 
    24     ll ret = 0;
    25     for(int i=0;i<=d;i++)
    26     {
    27         ret += dfs(pos-1,sum+val[i],flag||i<d);
    28     }
    29     if(flag) ans = ret;
    30     return ret;
    31 }
    32 ll solve(ll x)
    33 {
    34     if(x == -1) return 0;
    35     // 要清空,因为下面固定从第7位开始
    36     memset(bit,0,sizeof bit);
    37     int pos = 0;
    38     while(x)
    39     {
    40         bit[pos++] = x % 16;
    41         x /= 16;
    42     }
    43 
    44     // 固定从第7位开始,因为前导0也算贡献
    45     return dfs(7,0,false);
    46 }
    47 
    48 int main()
    49 {
    50     scanf("%d",&T);
    51     memset(dp,-1,sizeof(dp));
    52     while(T--)
    53     {
    54         scanf("%d%s",&n,s);
    55         ll st = 0, ed = 0;
    56         for(int i=0;s[i];i++) st = st * 16 + get(s[i]);
    57         ed = st + n - 1;
    58         ll lim = 0;
    59         for(int i=0;s[i];i++) lim = lim * 16 + get('F');
    60         ll ans = 0;
    61         if(ed <= lim) ans = solve(ed) - solve(st - 1);
    62         else ans = solve(ed - lim - 1) + solve(lim) - solve(st - 1);
    63         printf("%lld
    ",ans);
    64     }
    65     return 0;
    66 }
    E

      

      F题,现场用线段树写,就写错了一个字母然后RE了QAQ,,把cnt[l]改成cnt[o]就A了。要注意的是因为在query内带修改,因此再返回前需要up一下(虽然只在最后up,返回前没up也能够A)。线段树代码如下:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #include <set>
      5 #include <vector>
      6 #define t_mid (l+r>>1)
      7 #define ls (o<<1)
      8 #define rs (o<<1|1)
      9 #define lson ls,l,t_mid
     10 #define rson rs,t_mid+1,r
     11 using namespace std;
     12 const int N = 1e5 + 5;
     13 
     14 int a[N];
     15 int fa[N];
     16 vector<int> v[N],ans[N];
     17 int cnt[N<<2];
     18 
     19 int n;
     20 int get_fa(int u)
     21 {
     22     if(fa[u] == -1) return u;
     23     else return fa[u] = get_fa(fa[u]);
     24 }
     25 void up(int o) {cnt[o] = cnt[ls] + cnt[rs];}
     26 int query(int o,int l,int r,int pos)
     27 {
     28     if(l == r)
     29     {
     30         if(cnt[o] == 0) return -1;
     31         else
     32         {
     33             cnt[o]--;
     34             int t = v[l].back(); v[l].pop_back();
     35             return t;
     36         }
     37     }
     38     if(pos > t_mid && cnt[rs] > 0)
     39     {
     40         int t = query(rson,pos);
     41         up(o);
     42         if(t != -1) return t;
     43         else
     44         {
     45             if(cnt[ls] == 0) return -1;
     46             else
     47             {
     48                 int ret = query(lson,pos);
     49                 up(o);
     50                 return ret;
     51             }
     52         }
     53     }
     54 
     55     if(cnt[ls] == 0) return -1;
     56     else
     57     {
     58         int ret = query(lson,pos);
     59         up(o);
     60         return ret;
     61     }
     62     //up(o);
     63 }
     64 void update(int o,int l,int r,int pos)
     65 {
     66     if(l == r)
     67     {
     68         cnt[o] += 2;
     69         return ;
     70     }
     71     if(t_mid >= pos) update(lson,pos);
     72     else update(rson,pos);
     73     up(o);
     74 }
     75 void build(int o,int l,int r)
     76 {
     77     cnt[o] = 0;
     78     if(l == r) return ;
     79     build(lson);
     80     build(rson);
     81 }
     82 
     83 int main()
     84 {
     85     int T;
     86     scanf("%d",&T);
     87     while(T--)
     88     {
     89         scanf("%d",&n);
     90         for(int i=1;i<=n;i++) fa[i] = -1;
     91         build(1,1,n);
     92         for(int i=1;i<=n;i++) scanf("%d",a+i);
     93         for(int i=1;i<=n;i++)
     94         {
     95             ans[i].clear();
     96             v[i].clear();
     97         }
     98         for(int i=1;i<=n;i++)
     99         {
    100             int t = query(1,1,n,a[i]);
    101             fa[i] = t;
    102             update(1,1,n,a[i]);
    103             v[a[i]].push_back(i);
    104             v[a[i]].push_back(i);
    105         }
    106         for(int i=1;i<=n;i++) get_fa(i);
    107         for(int i=1;i<=n;i++)
    108         {
    109             if(fa[i] != -1) ans[fa[i]].push_back(i);
    110             else ans[i].push_back(i);
    111         }
    112         int ans_cnt = 0;
    113         for(int i=1;i<=n;i++) if(ans[i].size()) ans_cnt++;
    114         printf("%d
    ",ans_cnt);
    115         for(int i=1;i<=n;i++)
    116         {
    117             if(ans[i].size())
    118             {
    119                 printf("%d",ans[i].size());
    120                 for(int j=0;j<ans[i].size();j++) printf(" %d",ans[i][j]);
    121                 puts("");
    122             }
    123         }
    124     }
    125     return 0;
    126 }
    F(线段树)

    另外比赛的时候就想到了贪心的方法,每次选择不超过a[i]的最大的能插入的数字后面插入即可(不能插入就新建一棵树),当时因为以为set没有lower_bound(以为这是线性的),所以找不到一个容器能够在log的时间内查找,删除和插入,故没用这个方法写。事实上,set自带的成员函数lower_bound是log的,而如果lower_bound里面丢set的话复杂度要高很多(这似乎是一个STL经常遇到的问题。。)。如果知道了set也能够log的时间内查找的话,代码就不难写了。代码如下:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #include <set>
      5 #include <vector>
      6 using namespace std;
      7 const int N = 1e5 + 5;
      8 
      9 int a[N];
     10 int fa[N];
     11 vector<int> ans[N];
     12 
     13 struct node
     14 {
     15     int val, id, cnt;
     16     bool operator < (const node & temp) const
     17     {
     18         if(val == temp.val)
     19         {
     20             if(id == temp.id) return cnt < temp.cnt;
     21             else return id < temp.id;
     22         }
     23         else return val < temp.val;
     24     }
     25 };
     26 set<node> S;
     27 int n;
     28 int get_fa(int u)
     29 {
     30     if(fa[u] == -1) return u;
     31     else return fa[u] = get_fa(fa[u]);
     32 }
     33 
     34 int main()
     35 {
     36     set<node>::iterator it, temp;
     37     int T;
     38     scanf("%d",&T);
     39     while(T--)
     40     {
     41         int cnt = 1;
     42         scanf("%d",&n);
     43         S.clear();
     44         //for(int i=1;i<=n;i++) fa[i] = -1;
     45         int maxn = 0;
     46         for(int i=1;i<=n;i++) scanf("%d",a+i), maxn = max(maxn, a[i]);
     47         for(int i=1;i<=n;i++) ans[i].clear();
     48         for(int i=1;i<=n;i++)
     49         {
     50             if(S.size() == 0)
     51             {
     52                 S.insert((node){a[i], i, 0});
     53                 fa[i] = -1;
     54                 continue;
     55             }
     56             it = S.lower_bound((node){a[i], -1, -1});
     57             if(it == S.end())
     58             {
     59                 node now = *S.rbegin();
     60                 fa[i] = now.id;
     61                 now.cnt++;
     62                 S.erase(*S.rbegin());
     63                 if(now.cnt < 2) S.insert(now);
     64             }
     65             else
     66             {
     67                 if(it->val == a[i])
     68                 {
     69                     node now = *it;
     70                     fa[i] = now.id;
     71                     now.cnt++;
     72                     S.erase(*it);
     73                     if(now.cnt < 2) S.insert(now);
     74                 }
     75                 else
     76                 {
     77                     if(it == S.begin())
     78                     {
     79                         cnt ++;
     80                         fa[i] = -1;
     81                     }
     82                     else
     83                     {
     84                         it--;
     85                         node now = *it;
     86                         fa[i] = now.id;
     87                         now.cnt++;
     88                         S.erase(*it);
     89                         if(now.cnt < 2) S.insert(now);
     90                     }
     91                 }
     92             }
     93 
     94             S.insert((node){a[i], i, 0});
     95         }
     96         for(int i=1;i<=n;i++) get_fa(i);
     97         for(int i=1;i<=n;i++)
     98         {
     99             if(fa[i] == -1) ans[i].push_back(i);
    100             else ans[fa[i]].push_back(i);
    101         }
    102         printf("%d
    ",cnt);
    103         for(int i=1;i<=n;i++)
    104         {
    105             if(ans[i].size())
    106             {
    107                 printf("%d",ans[i].size());
    108                 for(int j=0;j<ans[i].size();j++) printf(" %d",ans[i][j]);
    109                 puts("");
    110             }
    111         }
    112     }
    113     return 0;
    114 }
    F(set)

    另外要注意的是题目说所有的n加起来不超过2e6,但是没说T的大小,因此T可能很多(事实上就是如此,有很多n很小的数据),因此不能够用memset直接初始化所有的数据,否则会T。

      H题,是个xjbg题,主要思想就是分治递归,代码细节可能有点多,就直接丢队友AC的代码了:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5+100;
     4 
     5 int a[N],b[N],aid[N],bid[N];
     6 int ans[N];
     7 int dfs(int al,int ar,int bl,int br,int f){
     8     if(al == ar) {
     9         ans[a[al]] = a[f];
    10         return -1;
    11     }
    12     if(a[al] == b[bl]){
    13         ans[a[al]] = a[f];
    14         int tmp = dfs(al+1,ar,bl+1,br,al);
    15         if(tmp == -1) return -1;
    16         if(a[al+1] == b[bl+1])
    17             return dfs(tmp,ar,bid[a[tmp]],br,al);
    18         else return tmp;
    19     }
    20     else{
    21         dfs(al,aid[b[bl]]-1,bid[a[al]],bid[a[al]]+aid[b[bl]]-al-1,f);
    22         dfs(aid[b[bl]],aid[b[bl]]+bid[a[al]]-bl-1,bl,bid[a[al]]-1,f);
    23         if(aid[b[bl]]+bid[a[al]]-bl > ar) return -1;
    24         return aid[b[bl]]+bid[a[al]]-bl;
    25     }
    26 }
    27 
    28 int main(){
    29     int T;
    30     cin >> T;
    31     while(T--){
    32         int n;
    33         scanf("%d",&n);
    34         for(int i= 1;i <= n;i ++){
    35             int now;
    36             scanf("%d",&now);
    37             a[i] = now;
    38             aid[now] = i;
    39         }
    40         for(int i= 1;i <= n;i ++){
    41             int now;
    42             scanf("%d",&now);
    43             b[i] = now;
    44             bid[now] = i;
    45         }
    46         dfs(1,n,1,n,0);
    47         for(int i= 1;i <= n; i++){
    48             printf("%d%c",ans[i],i==n?'
    ':' ');
    49         }
    50     }
    51     return 0;
    52 }
    H题

      G题,是个博弈论题,感觉是个莽题,只要胆子大敢交就能A。根据nim游戏的定义,先手者为了能赢肯定是要模仿后手的行动,但是此时先手者存在奇偶限制,故不能够完全模仿后手(比如先手只能拿奇时后手可以拿偶来逃出必败态)。所以先手为了能赢必须要在第一手去掉所有的限制,那么就转化成了Bob先手的nim游戏了。同时需要一些特判,比如如果限制堆过多(大于1),先手是不能够一次拿完的,因此必败;如果存在一堆,先手只能拿偶数,但是是奇数堆,很显然Alice是无论如何都不可能拿掉这堆的最后一个的,因此必败。另外需要注意,如果某堆个数是1且限制是只能拿奇数个,那么这堆和没有限制一样。代码如下:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 using namespace std;
     5 const int N = 1e5 + 5;
     6 
     7 int a[N],b[N];
     8 int T,n;
     9 bool solve()
    10 {
    11     int cnt1 = 0, cnt2 = 0;
    12     for(int i=1;i<=n;i++)
    13     {
    14         if(b[i] == 2 && a[i] % 2) return false;
    15         if(b[i] == 1 && a[i] > 1) cnt1++;
    16         else if(b[i] == 2) cnt2++;
    17     }
    18     if(cnt1 + cnt2 >= 2) return false;
    19     int ans = 0;
    20     for(int i=1;i<=n;i++)
    21     {
    22         if(b[i] == 1 && a[i] > 1) ans ^= (a[i] % 2 ? 0 : 1);
    23         else if(b[i] == 2) ans ^= 0;
    24         else ans ^= a[i];
    25     }
    26     if(cnt1 + cnt2 == 1) return ans ? 0 : 1;
    27     else return ans ? 1 : 0;
    28 }
    29 
    30 int main()
    31 {
    32     scanf("%d",&T);
    33     while(T--)
    34     {
    35         scanf("%d",&n);
    36         for(int i=1;i<=n;i++) scanf("%d",a+i);
    37         for(int i=1;i<=n;i++) scanf("%d",b+i);
    38         puts(solve() ? "Alice" : "Bob");
    39     }
    40     return 0;
    41 }
    G题

      最后,今年省赛晚饭没有饮料和水果供应,差评!不过在食堂遇到了多年没见的老同学也还是挺开心的~

  • 相关阅读:
    【思考题】任意长度有理数乘法运算
    【排序】表插入排序算法(C语言版)
    JAVA中的反射
    JAVA中关于日期的最常见的操作
    Hibernate:基于HQL实现数据查询
    Hibernate与Mybatis对比
    使用idea实现SSM框架整合
    基于maven搭建hibernate运行环境
    MYSQL中的存储过程
    MySQL 索引
  • 原文地址:https://www.cnblogs.com/zzyDS/p/6766902.html
Copyright © 2011-2022 走看看