2017年浙江省赛总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",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\n",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\n",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?\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题

 

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

以上是关于2017年浙江省赛总结的主要内容,如果未能解决你的问题,请参考以下文章

2017年浙江中医药大学大学生程序设计竞赛(重现赛)D - CC的神奇背包

2017年浙江中医药大学大学生程序设计竞赛(重现赛)A - 不存在的树

2019省赛训练组队赛4.9周二 2017浙江省赛

2018省赛模拟赛1(2017浙江省赛)

2017浙江省赛 A - Cooking Competition ZOJ - 3958

2017师大省赛总结