• 2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest


    哎,前方的路还很长。

    A. Auxiliary Project

    题意:考虑LED灯上显示0-9每个数字需要点亮的灯管数。给你一个n,不超过1e6,问你恰好点亮n个灯管可以点亮的数字的和,最大是多少

    观察:n不是很大,可以背包。也可以找找规律,小规模打表,O(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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const int maxn = 1e6+1;
    27 int f[maxn], n;
    28 int c[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
    29 int main()
    30 {
    31     freopen("auxiliary.in", "r", stdin);
    32     freopen("auxiliary.out", "w", stdout);
    33     scanf("%d", &n);
    34     fill(f, f+1+n, -1e9);
    35     f[0] = 0;
    36     for (int i = 0; i < 10; ++i)
    37         for (int j = c[i]; j <= n; ++j)
    38             f[j] = max(f[j], f[j-c[i]]+i);
    39     printf("%d
    ", f[n]);
    40 }
    View 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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const int maxn = 1e6+1;
    27 int f[maxn], n;
    28 int c[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
    29 int cc[3] = {1, 7, 4};
    30 inline int solve(int a)
    31 {
    32     a -= 2;
    33     return cc[a%3] + a/3*7;
    34 }
    35 int main()
    36 {
    37     freopen("auxiliary.in", "r", stdin);
    38     freopen("auxiliary.out", "w", stdout);
    39     scanf("%d", &n);
    40     printf("%d
    ", solve(n));
    41 }
    View Code

    B. Boolean Satisfiability

    题意:不超过26个boolean 变量,使用的符号只有变量名,“非”(negation)和 “或” (or)。问你有多少种赋值方式使得表达式为True。

    观察:令出现的变量个数为cnt。如果一个变量x和非x同时出现,那么表达式一定为True,所有变量值随便取,答案是2^cnt。否则,至少有一个变量的值应该为True,答案是(2^cnt) - 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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 map<char, set<int> > ma;
    27 const int maxn = 1e3+1;
    28 char s[maxn];
    29 int main()
    30 {
    31     freopen("boolean.in", "r", stdin);
    32     freopen("boolean.out", "w", stdout);
    33     scanf("%s", s);
    34     int last = -1, ptr = 0, n = strlen(s);
    35     while (ptr < n)
    36     {
    37         if (s[ptr] == '|');
    38         else if (s[ptr] == '~')
    39         {
    40             ++ptr;
    41             ma[s[ptr]].insert(1);
    42         }
    43         else
    44         {
    45             ma[s[ptr]].insert(0);
    46         }
    47         ++ptr;
    48     }
    49     for (const auto &e : ma)
    50         if (e.second.size() > 1)
    51         {
    52             printf("%lld
    ", 1ll<<ma.size());
    53             return 0;
    54         }
    55     printf("%lld
    ", -1 + (1ll<<ma.size()));
    56     
    57 }
    View Code

    C. Consonant Fencity

    题意:给你一个长度不超过1e6的只有小写字母组成的字符串。定义aeiouwy这7个字母为元音,其余的字母为辅音。对于一个字符串,它的美丽度是相邻且大小写不同的辅音对的个数。允许你把一些字母变成大写(同一种字母大小写必须相同),让你输出美丽值最大的字符串。

    观察:辅音有19个,可以暴力枚举19个大小写情况,每次检查有多少个美丽的辅音对。暴力枚举是2^19。但是因为大小写颠倒不影响答案,其实可以固定某一个辅音的大小写,枚举剩下18个的大小写,2^18。然后辅音对可以用一个int cnt[19][19]预处理出来,对于每一种大小写情况,19*19的暴力统计。

    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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const string vowel = "aeiouwy";
    27 int s[300];
    28 char id[30];
    29 int cnt[30][30];
    30 char str[1000001];
    31 int solve(int mask)
    32 {
    33     int ans = 0;
    34     for (int i = 1; i <= s['z']; ++i)
    35         for (int j = 1; j <= s['z']; ++j)
    36             if (((mask>>i-1)&1)^((mask>>j-1)&1))
    37             {
    38                 //if (cnt[i][j]) cerr << id[i] << " " << id[j] << " " << cnt[i][j] << endl;
    39                 ans += cnt[i][j];
    40             }
    41     return ans;
    42 }
    43 /*
    44  16436
    45  */
    46 char perm[300];
    47 int main()
    48 {
    49     freopen("consonant.in", "r", stdin);
    50     freopen("consonant.out", "w", stdout);
    51     for (char c = 'a'; c <= 'z'; ++c)
    52         s[c] = 1;
    53     for (auto c : vowel)
    54         s[c] = 0;
    55     int tot = 0;
    56     for (char c = 'a'; c <= 'z'; ++c)
    57         if (s[c])
    58         {
    59             s[c] = ++tot;
    60         }
    61     for (char c = 'a'; c <= 'z'; ++c)
    62         if (s[c])
    63             id[s[c]] = c;
    64     scanf("%s", str);
    65     int n = strlen(str);
    66     for (int i = 0; i < n-1; ++i)
    67         cnt[s[str[i]]][s[str[i+1]]] += 1;
    68     int ans = 0, mask = 0;
    69     for (int i = 0; i < (1<<18); ++i)
    70     {
    71         int tmp = solve(i);
    72         if (tmp > ans)
    73             ans = tmp, mask = i;
    74     }
    75     for (char c = 'a'; c <= 'z'; ++c)
    76         perm[c] = c;
    77     for (int i = 1; i <= s['z']; ++i)
    78         if ((mask>>i-1)&1)
    79             perm[id[i]] = id[i]+'Z'-'z';
    80     for (int i = 0; i < n; ++i)
    81         putchar(perm[str[i]]);
    82     puts("");
    83 
    84 }
    View Code

    D. Dividing Marbles

    E. Equal Numbers

    题意:给你一个长度不超过3e5,元素都不超过1e6的正整数数列a[]。一次操作允许你将其中一个元素乘上任意一个正整数。对于k = 0,1,2, ..., n,让你输出进行k次操作,数列中不同数值个数的最小值。

    观察:当k = n时,我们一定可以使所有元素相同,即把所有数都变成a[1] - a[n]的一个公倍数CM。所以操作可以简化成两类,一类是将某个a[i] 变成一个数列中存在的a[j],为了方便理解可以直接把a[j]选作数列中出现的a[i]倍数里最大的一个;或者把某个a[i]变成最终的CM。这样的话,也就可以把数列中初始的数分成两类,有后继的数(后继指数列中出现的自己的倍数)和没后继的数。注意,为了使不同数值的个数降低,我们需要把某一个数值的所有元素一起变换才会有效,所以要贪心的取出现次数最少的。计算答案的时候只需要考虑两种情况,就是CM已经出现,或者CM还未出现。

    方法:为了图省事,写了前缀和加二分答案。其实是可以使用滑动窗口来做。

    code:

    下面第一种写法的意思是,要么不考虑生成CM。如果考虑生成CM,就一定要至少取一个没有后继的数。

     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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const int maxn = 1e6+1;
    27 int cnt[maxn], n;
    28 int main()
    29 {
    30     freopen("equal.in", "r", stdin);
    31     freopen("equal.out", "w", stdout);
    32     scanf("%d", &n);
    33     for (int i = 0; i < n; ++i)
    34     {
    35         int x;
    36         scanf("%d", &x);
    37         ++cnt[x];
    38     }
    39     vector<int> a, b;
    40     for (int i = 1; i < maxn; ++i)
    41         if (cnt[i])
    42         {
    43             bool done = false;
    44             for (int j = 2*i; j < maxn; j += i)
    45                 if (cnt[j])
    46                 {
    47                     done = true;
    48                     break;
    49                 }
    50             if (done)
    51                 b.pb(cnt[i]);
    52             else
    53                 a.pb(cnt[i]);
    54         }
    55     int tot = a.size() + b.size();
    56     swap(a.back(), *min_element(a.begin(), a.end()));
    57     int mini = a.back();
    58     a.pop_back();
    59     b.pb(0);
    60     a.insert(a.end(), b.begin(), b.end());
    61     sort(a.begin(), a.end());
    62     sort(b.begin(), b.end());
    63     for (int i = 1;  i < a.size(); ++i)
    64         a[i] += a[i-1];
    65     for (int j = 1; j < b.size(); ++j)
    66         b[j] += b[j-1];
    67     for (int i = 0; i <= n; ++i)
    68     {
    69         int ans = tot - max(upper_bound(a.begin(), a.end(), i-mini)-a.begin()-1,(upper_bound(b.begin(), b.end(), i)-b.begin()-1));
    70         printf("%d%c", ans, i==n?'
    ':' ');
    71     }
    72 
    73 }
    View Code

     反思之后下面第二种写法会比较容易理解,即要么不考虑生成CM,要么生成CM,但是会浪费一次变换的机会(因为CM原本未在数列中出现,第一次把一类数变成CM不会使答案下降)。

     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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const int maxn = 1e6+1;
    27 int cnt[maxn], n;
    28 int main()
    29 {
    30     freopen("equal.in", "r", stdin);
    31     freopen("equal.out", "w", stdout);
    32     scanf("%d", &n);
    33     for (int i = 0; i < n; ++i)
    34     {
    35         int x;
    36         scanf("%d", &x);
    37         ++cnt[x];
    38     }
    39     vector<int> a, b;
    40     for (int i = 1; i < maxn; ++i)
    41         if (cnt[i])
    42         {
    43             for (int j = 2*i; j < maxn; j += i)
    44                 if (cnt[j])
    45                 {
    46                     b.pb(cnt[i]);
    47                     break;
    48                 }
    49                 a.pb(cnt[i]);
    50         }
    51     int tot = a.size();
    52     b.pb(0);
    53     a.pb(0);
    54     sort(a.begin(), a.end());
    55     sort(b.begin(), b.end());
    56     for (int i = 1;  i < a.size(); ++i)
    57         a[i] += a[i-1];
    58     for (int j = 1; j < b.size(); ++j)
    59         b[j] += b[j-1];
    60     for (int i = 0; i <= n; ++i)
    61     {
    62         int ans = tot - max(upper_bound(a.begin(), a.end(), i)-a.begin()-2,(upper_bound(b.begin(), b.end(), i)-b.begin()-1));
    63         printf("%d%c", ans, i==n?'
    ':' ');
    64     }
    65 
    66 }
    View Code

    I. Intelligence in Perpendicularia

    题意:给你一个不超过1000个点的简单多边形。每条边水平或者竖直。问你用不能从沿x轴或者y轴看到的边长有多少。

    观察:其实就是多边形周长长减去最小外接长方形的周长。

    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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 const int maxn = 1e3+1;
    27 int x[maxn], y[maxn], n;
    28 
    29 int main()
    30 {
    31     freopen("intel.in", "r", stdin);
    32     freopen("intel.out", "w", stdout);
    33     scanf("%d", &n);
    34     for (int i = 0; i < n; ++i)
    35         scanf("%d %d", x+i, y+i);
    36     int ans =  0;
    37     for (int i = 0; i < n; ++i)
    38         ans += abs(x[(i+1)%n]-x[i]) + abs(y[(i+1)%n]-y[i]);
    39     ans -= 2*(*max_element(x, x+n)-*min_element(x, x+n) + *max_element(y, y+n)-*min_element(y, y+n));
    40     printf("%d
    ", ans);
    41 }
    View Code

    K. Kotlin Island

    题意:在一块h*w的土地上(h,w <=100),你可以横向或者纵向挖水沟。给你一个n,不超过1e9,让你输出一种使得水沟外,剩下陆地联通块个数为n的方案。

    观察:对于一个纬度x,最多可以将其分成(x+1)/2条(切(x-1)/2刀)。所以可以如果可以把n分解成a*b的形式,且 min(a, b) <= (min(w, h)+1)/2, max(a, b) <= (max(w, h)+1)/2,那么就有解。

    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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 
    27 const int maxn = 1e2+1;
    28 char s[maxn][maxn];
    29 int w, h, n;
    30 void solve(int wl, int hl)
    31 {
    32     --wl, --hl;
    33     for (int i = 1; i <= wl; ++i)
    34         for (int j = 0; j < h; ++j)
    35             s[2*i-1][j] = '#';
    36     for (int j = 1; j <= hl; ++j)
    37         for (int i = 0; i < w; ++i)
    38             s[i][2*j-1] = '#';
    39     for (int i = 0; i < w; ++i)
    40         puts(s[i]);
    41     exit(0);
    42 }
    43 int main()
    44 {
    45     freopen("kotlin.in", "r", stdin);
    46     freopen("kotlin.out", "w", stdout);
    47     scanf("%d %d %d", &w, &h, &n);
    48     for (int i = 0; i < w; ++i)
    49     {
    50         fill(s[i], s[i]+h, '.');
    51         s[i][h] = 0;
    52     }
    53     int wl = (w+1)/2, hl = (h+1)/2;
    54     for (int i = 1; i <= wl; ++i)
    55         if (n%i == 0 && n/i <= hl)
    56             solve(i, n/i);
    57     puts("Impossible");
    58 }
    View Code

    L. Little Difference

    题意:给你一个n,不超过1e18。让你把n分解成若干正因子的积,且任意两个因子间差不超过1。让你以任意顺序输出所有方案,如果有无限种方案,输出-1。

    观察:如果n是2的自然数幂,那么n有无穷组分解,因为可以在分解中加任意个数的1。其他情况都有有限解。注意到{n}本身是一个解,然后如果分解成两个数,那么其中一定有一个是ceil(sqrt(n)),特判一下这种情况。最后如果解中的元素不少于3个,那么最小的元素肯定不超过1e6,暴力枚举每一个最小的元素即可。

    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 typedef unsigned long long ull;
    23 #define mp make_pair
    24 #define pb push_back
    25 
    26 vector<vector<ll> > ans;
    27 ll n;
    28 void test(ll x, ll n)
    29 {
    30     if (x == 1 || n % x != 0)
    31         return;
    32     vector<ll> v;
    33     while (n % x == 0)
    34         n /= x, v.pb(x);
    35     while (n % (x+1) == 0)
    36         n /= x+1, v.pb(x+1);
    37     if (n == 1)
    38         ans.pb(v);
    39 }
    40 bool pow2(ll n)
    41 {
    42     while (n % 2 == 0)
    43         n >>= 1;
    44     return n == 1;
    45 }
    46 int main()
    47 {
    48     //freopen("little.in", "r", stdin);
    49     //freopen("little.out", "w", stdout);
    50     scanf("%lld", &n);
    51     if (pow2(n))
    52     {
    53         puts("-1");
    54         return 0;
    55     }
    56     ans.pb({n});
    57     ll root = sqrt(n+0.5);
    58     while (root*root <= n)
    59         ++root;
    60     while (root*root > n)
    61         --root;
    62     test(root, n);
    63     for (ll i = 2; i*i*i <= n; ++i)
    64         test(i, n);
    65     printf("%d
    ", ans.size());
    66     for (const auto &v : ans)
    67     {
    68         printf("%d", v.size());
    69         for (const auto e : v)
    70             printf(" %lld", e);
    71         putchar('
    ');
    72     }
    73 }
    View Code
  • 相关阅读:
    推流当中自适应码率的策略
    使用python实现人脸检测<转载>
    acm.njupt 1001-1026 简单题
    fedora 系统安装后常用设置
    一个普普通通的计算机研究生找工作的感悟
    一个简单的爬虫程序
    HDU 1005 Number Sequence
    【StatLearn】统计学习中knn算法的实验(1)
    SQL描述(2)
    连续点击返回键,退出应用程序
  • 原文地址:https://www.cnblogs.com/skyette/p/8440340.html
Copyright © 2020-2023  润新知