zoukankan      html  css  js  c++  java
  • Yandex Algorithm 2018 Qualification

    A. Lottery

    code:

     1 /*
     2  by skydog
     3  */
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <utility>
     8 #include <algorithm>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <map>
    12 #include <set>
    13 #include <stack>
    14 #include <queue>
    15 #include <deque>
    16 #include <cassert>
    17 #include <list>
    18 using namespace std;
    19 typedef long long ll;
    20 typedef pair<int, int> ii;
    21 typedef pair<ll, ll> l4;
    22 
    23 #define mp make_pair
    24 #define pb push_back
    25 #define db(x) cerr << #x << " = " << x << endl
    26 
    27 const int maxn = 32;
    28 bool vis[maxn+1] = {0};
    29 
    30 int main()
    31 {
    32     int a = 10, b = 6;
    33     for (int i = 0; i < a; ++i)
    34     {
    35         int x;
    36         scanf("%d", &x);
    37         vis[x] = true;
    38     }
    39     int T;
    40     scanf("%d", &T);
    41     for (int kase = 1; kase <= T; ++kase)
    42     {
    43         int cnt = 0;
    44         for (int i = 0; i < b; ++i)
    45         {
    46             int x;
    47             scanf("%d", &x);
    48             cnt += vis[x];
    49         }
    50         puts(cnt>=3?"Lucky":"Unlucky");
    51     }
    52 }
    View Code

    B. Permutation Recovery

    题意:对于一个n*n的permutation,n<=100,可以看作一个n*n的方阵。现将每一行看作一个长度为n的数列,每一列同理,n行和n列放在一起,打乱顺序。让你找出一组可能的permutation。保证输入有解。

    观察:permutation第一个元素会作为开头出现两次,其他元素至多作为开头出现一次。所以找到开头出现两次的元素,把其中一个数列当作第一列,然后将每一列开头元素对应的数列输出即可。

    code:

     1 /*
     2  by skydog
     3  */
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <utility>
     8 #include <algorithm>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <map>
    12 #include <set>
    13 #include <stack>
    14 #include <queue>
    15 #include <deque>
    16 #include <cassert>
    17 #include <list>
    18 using namespace std;
    19 typedef long long ll;
    20 typedef pair<int, int> ii;
    21 typedef pair<ll, ll> l4;
    22 
    23 #define mp make_pair
    24 #define pb push_back
    25 #define db(x) cerr << #x << " = " << x << endl
    26 
    27 const int maxn = 100+1;
    28 int n;
    29 vector<int> g[maxn*maxn];
    30 vector<int> tar;
    31 int main()
    32 {
    33     scanf("%d", &n);
    34     for (int i = 1; i <= 2*n; ++i)
    35     {
    36         vector<int> tmp(n);
    37         for (auto &e : tmp)
    38             scanf("%d", &e);
    39         if (g[tmp.front()].empty())
    40             g[tmp.front()] = tmp;
    41         else
    42             tar = tmp;
    43     }
    44     bool first = true;
    45     for (auto e : tar)
    46     {
    47         const auto &v = g[e];
    48         for (auto e : v)
    49         {
    50             if (first)
    51                 first = false;
    52             else
    53                 printf(" ");
    54             printf("%d", e);
    55         }
    56     }
    57     if (!first)
    58         puts("");
    59 }
    View Code

     WA:数组开小了。

    C. Beautiful Tables

    题意:给你一个n,不超过1000,让你在n*n的方阵中填1-n的数字,使得每一行的元素和 and 每一列的元素和都能被n整除。问你有多少种填的方案,答案mod 1e9+7。

    观察:对于左上角(n-1)*(n-1)的子方阵,随意填数,剩下最后一行和最后一列的数字就会被唯一确定,而且有解。所以答案就是n^[(n-1)*(n-1)]。

    code:

     1 /*
     2  by skydog
     3  */
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <utility>
     8 #include <algorithm>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <map>
    12 #include <set>
    13 #include <stack>
    14 #include <queue>
    15 #include <deque>
    16 #include <cassert>
    17 #include <list>
    18 using namespace std;
    19 typedef long long ll;
    20 typedef pair<int, int> ii;
    21 typedef pair<ll, ll> l4;
    22 
    23 #define mp make_pair
    24 #define pb push_back
    25 #define db(x) cerr << #x << " = " << x << endl
    26 
    27 const int mod = 1e9+7;
    28 ll power(ll base, ll p)
    29 {
    30     ll ret = 1;
    31     while (p)
    32     {
    33         if (p&1)
    34             ret = ret * base % mod;
    35         p >>= 1;
    36         base = base * base % mod;
    37     }
    38     return ret;
    39 }
    40 int main()
    41 {
    42     int n;
    43     scanf("%d", &n);
    44     printf("%lld
    ", power(n, (n-1)*(n-1)));
    45 }
    View Code

    D. Triangle Construction

    题意:给你n (n <= 3e5) 个长度不超过1e18的木棍,长度计作L[1-n]。有q (q <= 3e5) 组询问,每组询问形如(l, r), 1 <= l <= r <= n。让你找出[l, r]中三个下标不同的木棍,使得这三个木根可以构成一个三角形。如果找不到输出-1。

    观察:三条木棍能构成三角形,当且仅当最长边长度严格小于其余两条边长度和。可以想到,如果有一些木棍,找出一组可行解很简单,只需将木棍按照长度排序,然后从小到大找连续的三根木棍检查是否符合条件即可。如果找不到,便无解。

      为什么这样是对的。可以考虑枚举最长边,那么为了尽可能达到条件,剩下较短的两条边要选尽量长的,所以只需要考虑相邻的三根木棍就好了。

      下面考虑一下无解的情况,把长度排序,最坏的情况肯定是 1, 1, 2, 3, 5, 8, ....,即Fibonacci 数列。但是Fibonacci数列使呈指数级别增长的,算一下发现f[1] = f[2] = 1的Fibonacci数列第88项刚好超过1e18。所以如果木棍个数不小于88,那么一定可以找到解。

      所以对于每个询问就只用考虑min(88, r-l+1)个元素,排序后检查是否有解。这样不用预处理,令len = min(88, r-l+1),单次询问时间为O(len*log(len))。

      当然也可以先对每个位置l,暴力计算出使得[l, r]有解的最小的r,记作ans[l]。令len = min(88, n-l+1),这样处理一个l的复杂度是O(len*log(len)),整体处理所有l的话,令len = min(88, n),可以做到O(n*len*log(len))。单次询问O(1),例如询问[l, r]只需要看r和ans[l]的关系即可。如果r < ans[l],无解,否则直接输出答案即可。

      考虑了一下是否可以将上面这种方法利用滑动窗口之类的优化,但是好像不能避开最坏情况。

    code:

      无预处理,单次询问时间为O(len*log(len))。  

     1 /*
     2  by skydog
     3  */
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <utility>
     8 #include <algorithm>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <map>
    12 #include <set>
    13 #include <stack>
    14 #include <queue>
    15 #include <deque>
    16 #include <cassert>
    17 #include <list>
    18 using namespace std;
    19 typedef long long ll;
    20 typedef pair<int, int> ii;
    21 typedef pair<ll, ll> l4;
    22 
    23 #define mp make_pair
    24 #define pb push_back
    25 #define db(x) cerr << #x << " = " << x << endl
    26 
    27 
    28 /*
    29  by skydog
    30  */
    31 #include <iostream>
    32 #include <cstdio>
    33 #include <vector>
    34 #include <utility>
    35 #include <algorithm>
    36 #include <cmath>
    37 #include <cstring>
    38 #include <map>
    39 #include <set>
    40 #include <stack>
    41 #include <queue>
    42 #include <deque>
    43 #include <cassert>
    44 #include <list>
    45 using namespace std;
    46 typedef long long ll;
    47 typedef pair<int, int> ii;
    48 typedef pair<ll, ll> l4;
    49 
    50 #define mp make_pair
    51 #define pb push_back
    52 #define db(x) cerr << #x << " = " << x << endl
    53 
    54 const int maxn = 3e5+1;
    55 ll len[maxn];
    56 int maxl = 88;
    57 int n, q;
    58 void solve(int l, int r)
    59 {
    60     vector<l4> v;
    61     for (int i = l; i <= min(r, l+maxl-1); ++i)
    62         v.push_back(mp(len[i], i));
    63     sort(v.begin(), v.end());
    64     for (int i = 2; i < v.size(); ++i)
    65         if (v[i-2].first + v[i-1].first > v[i].first)
    66         {
    67             printf("%lld %lld %lld
    ", v[i-2].second, v[i-1].second, v[i].second);
    68             return;
    69         }
    70     puts("-1");
    71 }
    72 const ll inf = 1000000000000000000;
    73 int get_maxl()
    74 {
    75     ll a = 1, b = 1;
    76     int cnt = 2;
    77     while (b <= inf)
    78     {
    79         a += b;
    80         swap(a, b);
    81         ++cnt;
    82     }
    83     return cnt;
    84 }
    85 int main()
    86 {
    87     cerr << "maxl = " << (maxl = get_maxl()) << endl;
    88     scanf("%d %d", &n, &q);
    89     for (int i = 1; i <= n; ++i)
    90         scanf("%lld", len+i);
    91     for (int i = 1; i <= q; ++i)
    92     {
    93         int l, r;
    94         scanf("%d %d", &l, &r);
    95         solve(l, r);
    96     }
    97         
    98 }
    View Code

      O(n*len*log(len))预处理,O(1) 询问。

      1 /*
      2  by skydog
      3  */
      4 #include <iostream>
      5 #include <cstdio>
      6 #include <vector>
      7 #include <utility>
      8 #include <algorithm>
      9 #include <cmath>
     10 #include <cstring>
     11 #include <map>
     12 #include <set>
     13 #include <stack>
     14 #include <queue>
     15 #include <deque>
     16 #include <cassert>
     17 #include <list>
     18 using namespace std;
     19 typedef long long ll;
     20 typedef pair<int, int> ii;
     21 typedef pair<ll, ll> l4;
     22 
     23 #define mp make_pair
     24 #define pb push_back
     25 #define db(x) cerr << #x << " = " << x << endl
     26 
     27 
     28 /*
     29  by skydog
     30  */
     31 #include <iostream>
     32 #include <cstdio>
     33 #include <vector>
     34 #include <utility>
     35 #include <algorithm>
     36 #include <cmath>
     37 #include <cstring>
     38 #include <map>
     39 #include <set>
     40 #include <stack>
     41 #include <queue>
     42 #include <deque>
     43 #include <cassert>
     44 #include <list>
     45 using namespace std;
     46 typedef long long ll;
     47 typedef pair<int, int> ii;
     48 typedef pair<ll, ll> l4;
     49 
     50 #define mp make_pair
     51 #define pb push_back
     52 #define db(x) cerr << #x << " = " << x << endl
     53 
     54 const int maxn = 3e5+1;
     55 ll len[maxn];
     56 int ans[maxn];
     57 int ret[maxn][3];
     58 int maxl = 88;
     59 int n, q;
     60 
     61 const ll inf = 1000000000000000000;
     62 int get_maxl()
     63 {
     64     ll a = 1, b = 1;
     65     int cnt = 2;
     66     while (b <= inf)
     67     {
     68         a += b;
     69         swap(a, b);
     70         ++cnt;
     71     }
     72     return cnt;
     73 }
     74 multiset<l4> st;
     75 bool check(int from, int to, multiset<l4>::iterator a, multiset<l4>::iterator b, multiset<l4>::iterator c)
     76 {
     77     if (a->first + b->first > c->first)
     78     {
     79         ans[from] = to;
     80         ret[from][0] = a->second, ret[from][1] = b->second, ret[from][2] = c->second;
     81         return true;
     82     }
     83     return false;
     84 }
     85 void solve(int i)
     86 {
     87     st.clear();
     88     int lim = min(n, i+maxl-1);
     89     ans[i] = n+1;
     90     for (int j = i; j <= lim; ++j)
     91     {
     92         st.insert(mp(len[j], j));
     93         multiset<l4>::iterator it = st.find(mp(len[j], j)), it1, it2, it_1, it_2;
     94         it1 = it2 = it_1 = it_2 = st.end();
     95         if (it != st.end())
     96         {
     97             it1 = it;
     98             ++it1;
     99             if (it1 != st.end())
    100             {
    101                 it2 = it1;
    102                 ++it2;
    103             }
    104         }
    105         if (it != st.begin())
    106         {
    107             it_1 = it;
    108             --it_1;
    109             if (it_1 != st.begin())
    110             {
    111                 it_2 = it_1;
    112                 --it_2;
    113             }
    114         }
    115         if (it_1 != st.end())
    116         {
    117             if (it_2 != st.end() && check(i, j, it_2, it_1, it))
    118                 return;
    119             if (it1 != st.end() && check(i, j, it_1, it, it1))
    120                 return;
    121         }
    122         if (it1 != st.end() && it2 != st.end() && check(i, j, it, it1, it2))
    123             return;
    124     }
    125 }
    126 int main()
    127 {
    128     cerr << "maxl = " << (maxl = get_maxl()) << endl;
    129     scanf("%d %d", &n, &q);
    130     for (int i = 1; i <= n; ++i)
    131         scanf("%lld", len+i);
    132     int nxt = 1;
    133     for (int i = 1; i <= n; ++i)
    134         solve(i);
    135     for (int i = 1; i <= q; ++i)
    136     {
    137         int l, r;
    138         scanf("%d %d", &l, &r);
    139         if (r >= ans[l])
    140         {
    141             printf("%d %d %d
    ", ret[l][0], ret[l][1], ret[l][2]);
    142         }
    143         else
    144         {
    145             puts("-1");
    146         }
    147     }
    148         
    149 }
    View Code

    E.

    题意:给你两个string的序列A[1-n], B[1-k],1 <= n, k <= 1e5,每个字符串长度都不超过10,B中的字符串没有重复。问有多少个(l, r),1 <= l <= r <= n满足B中的每一个元素都在A[l-r]中出现过,即set{A[l-r]} 包含 set{B[1-k]}。

    观察:其实就是一个滑动窗口问题

    code:

     1 /*
     2  by skydog
     3  */
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <utility>
     8 #include <algorithm>
     9 #include <cmath>
    10 #include <cstring>
    11 #include <map>
    12 #include <set>
    13 #include <stack>
    14 #include <queue>
    15 #include <deque>
    16 #include <cassert>
    17 #include <list>
    18 using namespace std;
    19 typedef long long ll;
    20 typedef pair<int, int> ii;
    21 typedef pair<ll, ll> l4;
    22 
    23 #define mp make_pair
    24 #define pb push_back
    25 #define db(x) cerr << #x << " = " << x << endl
    26 
    27 const int maxn = 1e5+1;
    28 string s[maxn];
    29 int idx[maxn];
    30 map<string, int> id;
    31 int cnt[maxn] = {0}, tot = 0;
    32 int n, k;
    33 int main()
    34 {
    35     ios::sync_with_stdio(false);
    36     cin.tie(0);
    37     cin >> n >> k;
    38     for (int i = 1; i <= n; ++i)
    39         cin >> s[i];
    40     for (int i = 1; i <= k; ++i)
    41     {
    42         string str;
    43         cin >> str;
    44         id[str] = i;
    45     }
    46     for (int i = 1; i <= n; ++i)
    47         idx[i] = id[s[i]];
    48     ll ans = 0, nxt = 1;
    49     cnt[0] = 1;
    50     for (int i = 1; i <= n; ++i)
    51     {
    52         while (nxt <= n && tot < k)
    53         {
    54             if (cnt[idx[nxt]] == 0)
    55                 ++tot;
    56             ++cnt[idx[nxt]];
    57             ++nxt;
    58         }
    59         if (tot < k)
    60             break;
    61         ans += n-nxt+2;
    62         --cnt[idx[i]];
    63         if (cnt[idx[i]] == 0)
    64             --tot;
    65     }
    66     printf("%lld
    ", ans);
    67         
    68 }
    View Code

    F.

    题意:给你一颗大小不超过2e5的树,让你在树上选两个不同的点a和b。树上两点间的距离定义为两点间最短路径上的边数,树上一点的不稳定性定义为这个点到a或b距离的最小值,整棵树的不稳定性定义为,树上任意一点不稳定性的最大值。让你选出a,b使得树的不稳定性最小。

    观察:如果选一个点的话会选在哪呢?直径中点。那两个点是不是也会和直径有关?令直径上点的个数为len,那么最小的不稳定性不会超过len/2,因为你只要在直径的中点上放一个点(如果直径中点在一条边上,就在这条边两个端点上均放一个点),那么其他点到这个点(或两个点)的最小距离一定不超过len/2。那么其实可以考虑最小的不稳定性mini,mini <= len/2。如果答案是mini,那么我们只需要选离直径上距直径两端点距离为mini的点就好了(如果有重复,选另外的点)。所以可以考虑二分答案。

    code:

      1 /*
      2  by skydog
      3  */
      4 #include <iostream>
      5 #include <cstdio>
      6 #include <vector>
      7 #include <utility>
      8 #include <algorithm>
      9 #include <cmath>
     10 #include <cstring>
     11 #include <map>
     12 #include <set>
     13 #include <stack>
     14 #include <queue>
     15 #include <deque>
     16 #include <cassert>
     17 #include <list>
     18 using namespace std;
     19 typedef long long ll;
     20 typedef pair<int, int> ii;
     21 typedef pair<ll, ll> l4;
     22 
     23 #define mp make_pair
     24 #define pb push_back
     25 #define db(x) cerr << #x << " = " << x << endl
     26 
     27 const int maxn = 2e5+1;
     28 vector<int> g[maxn];
     29 int n, pre[maxn];
     30 int bfs(int cur)
     31 {
     32     int ret = -1;
     33     memset(pre, -1, sizeof(pre));
     34     pre[cur] = 0;
     35     queue<int> q;
     36     q.push(cur);
     37     while (!q.empty())
     38     {
     39         int cur = q.front();
     40         q.pop();
     41         ret = cur;
     42         for (auto nxt : g[cur])
     43             if (pre[nxt] == -1)
     44             {
     45                 pre[nxt] = cur;
     46                 q.push(nxt);
     47             }
     48     }
     49     assert(ret != -1);
     50     return ret;
     51 }
     52 vector<int> diameter;
     53 int dis[maxn];
     54 bool valid(int mid)
     55 {
     56     memset(dis, -1, sizeof(dis));
     57     queue<int> q;
     58     int a = diameter[mid], b = diameter[diameter.size()-1-mid];
     59     dis[a] = dis[b] = 0;
     60     q.push(a);
     61     q.push(b);
     62     while (!q.empty())
     63     {
     64         int cur = q.front();
     65         q.pop();
     66         if (dis[cur] > mid)
     67             return false;
     68         int nxtd = dis[cur]+1;
     69         for (auto nxt : g[cur])
     70             if (dis[nxt] == -1)
     71             {
     72                 dis[nxt] = nxtd;
     73                 q.push(nxt);
     74             }
     75     }
     76     return true;
     77 }
     78 int main()
     79 {
     80     scanf("%d", &n);
     81     for (int i = 1; i <= n-1; ++i)
     82     {
     83         int u, v;
     84         scanf("%d %d", &u, &v);
     85         g[u].pb(v);
     86         g[v].pb(u);
     87     }
     88     int lr = bfs(1);
     89     int rr = bfs(lr);
     90     //get diameter
     91     {
     92         int cur = rr;
     93         while (cur)
     94         {
     95             diameter.pb(cur);
     96             cur = pre[cur];
     97         }
     98         assert(diameter.back() == lr);
     99     }
    100     int half_len = diameter.size()/2;
    101     
    102     int l = 0, r = half_len, mid, ans=0;
    103     while (l <= r)
    104     {
    105         mid = (l+r)>>1;
    106         if (valid(mid))
    107         {
    108             ans = mid;
    109             r = mid-1;
    110         }
    111         else
    112             l = mid+1;
    113     }
    114     int a = diameter[ans], b = diameter[diameter.size()-ans-1];
    115     if (a == b)
    116         for (int i = 1; i <= n; ++i)
    117             if (i != a)
    118             {
    119                 b = i;
    120                 break;
    121             }
    122     printf("%d %d
    ", a, b);
    123 }
    View Code
  • 相关阅读:
    今天在这里开博客,分享心情与技术
    tp3.2控制器返回时关闭子窗口刷新父页面
    关于iframe与$.load()哪个更好
    javascript的匿名函数的理解(转载学习)
    DOM入门学习笔记
    SQL学习基础笔记
    多线程和套接字入门学习笔记
    网络套接字学习以及聊天程序开发实例
    DOM 讲解结束
    JQuery 基础学习
  • 原文地址:https://www.cnblogs.com/skyette/p/8452439.html
Copyright © 2011-2022 走看看