您的位置:首页 > 其它

Educational Codeforces Round 32【solved: 6 / 7】(F待补)

2017-11-10 16:51 585 查看
A - Local Extrema (模拟)

思路:根据题意模拟即可

#include <bits/stdc++.h>
using namespace std;
int a[1005];

int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)  scanf("%d", &a[i]);
int maxx = 0, minn = 0;

for(int i = 1; i <= n; i++)
{
if(i == 1 || i == n) continue;
if(a[i] > a[i - 1] && a[i] > a[i + 1])  maxx++;
if(a[i] < a[i - 1] && a[i] < a[i + 1])  minn++;
}
printf("%d\n", maxx + minn);
return 0;
}


B - Buggy Robot (简单思维)

思考一下左右上下对称即可

#include <bits/stdc++.h>
using namespace std;
char s[1005];

int main()
{
int n;
scanf("%d", &n);
scanf("%s", s);
int cntl = 0, cntr = 0, cntu = 0, cntd = 0;
for(int i = 0; i < n; i++)
{
if(s[i] == 'L') cntl++;
else if(s[i] == 'R')    cntr++;
else if(s[i] == 'U')    cntu++;
else if(s[i] == 'D')    cntd++;
}
int ans = 0;
ans = min(cntl, cntr) * 2 + min(cntu, cntd) * 2;
printf("%d\n", ans);
return 0;
}


C - K-Dominant Character (二分)

二分长度,枚举26个字母,挨个check一遍。

#include <bits/stdc++.h>
using namespace std;
char s[100000 + 5];
int cnt[30], len;

bool judge(int mid)
{
int n = len;
bool ok = false;
for(int i = 0; i < 26; i++)
{
char ch = 'a' + i;
int cnt = 0;
for(int j = 0; j < mid; j++)    if(s[j] == ch)  cnt++;
if(cnt == 0)    continue;
for(int j = mid; j
f922
< n; j++)
{
if(s[j - mid] == ch)    cnt--;
if(s[j] == ch)  cnt++;
if(cnt == 0)    break;
}
if(cnt == 0)    continue;
else return true;
}
return false;
}
int main()
{
scanf("%s", s);
len = strlen(s);
int lb = 1, rb = len;
while(lb < rb)
{
int mid = (lb + rb) / 2;
if(judge(mid))  rb = mid;
else lb = mid + 1;
}
printf("%d\n", rb);
return 0;
}


D - Almost Identity Permutations(错排)

思路:错排公式,枚举0-k个不错排的人。加和即可

#include <bits/stdc++.h>
using namespace std;
int d[] = {0, 0, 1, 2, 9, 44};
long long C(int n, int m)
{
long long ret = 1;
for(int i = n - m + 1; i <= n; i++) ret = ret * i;
for(int i = 1; i <= m; i++) ret /= i;
return ret;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
long long ans = 0;
for(int i = 0; i <= k; i++)
{
long long temp = 1LL * C(n, i) * d[i];
ans += temp;
}
printf("%lld\n", ans + 1);
return 0;
}


E - Maximum Subsequence (折半搜索)

思路:

  对前一半个数字进行状压dp,找到他们加和的结果,丢到vector里面去重。然后去对后一半的数字进行相同的操作,去前一半已经计算出的结果里找到匹配项。

  前一半的数的加和的结果 所在的 集合叫做S好了。 然后后一半数字计算出来的叫做val好了。取模是对m取模的。

  那么我们找的时候,考虑到取模的特殊性,一定是S中,小于m-val的数里头最大的,或者是S当中最大的,和val加和,才有可能产生最大值。前者是加和以后最接近m,后者是希望取模以后最接近m。

#include <bits/stdc++.h>
using namespace std;
int a[40];

int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)  scanf("%d", &a[i]);
int lpart = (n + 1) / 2, rpart = n - lpart;

vector<int>vec;
for(int S = 0; S < (1 << lpart); S++)
{
int temp = 0;
for(int j = 0; j < lpart; j++)
{
if(S & (1 << j))    temp = (temp + a[j]) % m;
}
vec.push_back(temp);
}
sort(vec.begin(), vec.end());
vec.resize(unique(vec.begin(), vec.end()) - vec.begin());
int maxx = *max_element(vec.begin(), vec.end());
int ans = 0;

for(int S = 0; S < (1 << rpart); S++)
{
int temp = 0;
for(int j = lpart; j < n; j++)
{
int idx = j - lpart;
if(S & (1 << idx))  temp = (temp + a[j]) % m;
}
ans = max(ans, (temp + maxx) % m);

int lb = 0, rb = vec.size() - 1;
while(lb < rb)
{
int mid = (lb + rb + 1) / 2;
if(vec[mid] < m - temp)    lb = mid;
else rb = mid - 1;
}
ans = max(ans, (temp + vec[rb]) % m);
}
printf("%d\n", ans);
return 0;
}


G - Xor-MST (01字典树+贪心+最小异或生成树)

给你n个点,每条边的边权是两个点的异或和,问你形成最小生成树,需要的代价是多少。(n≤200000,ai≤230)

思路:把数都插到字典树里面,然后考虑两个数的合并,最小代价的话,应该是尽可能相同的多,所以可以看做是两个子树的合并,那么插的时候记录一个siz,采取dfs,发现点root有左右儿子结点的时候,就可以合并了,合并的方式是枚举较小的子树中的每一个数,然后跑到另一个子树里去查最小异或和,更新答案。

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 200000 + 5;

typedef long long LL;
long long ans, cost;

struct Trie
{
int ch[32*maxn][2], siz[32*maxn], val[32*maxn], num[32*maxn], sz;
int up = 30;
init(){sz = 1;memset(ch[0], 0, sizeof(ch[0]));}
void Insert(int x)
{
int u = 0;
for(int i = up; i >= 0; i--)
{
int c = ((x >> i) & 1);
if(ch[u][c] == 0)
{
memset(ch[sz], 0, sizeof(ch[sz]));
num[sz] = val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
num[u] ++;
}
val[u] = x;
}
int getSize(int x)
{
if(!ch[x][0] && !ch[x][1])  return siz[x] = 1;
if(ch[x][0])    siz[x] += getSize(ch[x][0]);
if(ch[x][1])    siz[x] += getSize(ch[x][1]);
return siz[x];
}

void dfs(int x)
{
if(ch[x][0]) dfs(ch[x][0]);
if(ch[x][1]) dfs(ch[x][1]);

if(ch[x][0] && ch[x][1])
{//要合并root = x,这个结点的左右儿子。
cost = INF;
int lson = ch[x][0], rson = ch[x][1];
if(siz[lson] < siz[rson])   calc(lson, x);
else calc(rson, x);
ans += cost;
}
}

void calc(int x, int pre)
{//遍历root左右子树中较小一颗的所有数。
if(ch[x][0]) calc(ch[x][0], pre);
if(ch[x][1]) calc(ch[x][1], pre);

if(!ch[x][0] && !ch[x][1])
{
int now = query(val[x], pre);
if(cost > (val[now] ^ val[x]))
{
cost = (val[now] ^ val[x]);
}
}
}
int query(int x, int pre)
{//pre标记之前要合并左右儿子的根结点root。
int u = 0;
for(int i = up; i >= 0; i--)
{
int c = ((x >> i) & 1);
if(ch[u][c] == 0)   c = 1 - c;
if(u == pre)    c = 1 - c;
u = ch[u][c];
}
return u;
}
}trie;

int main()
{
trie.init();
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
trie.Insert(x);
}
trie.getSize(0);
trie.dfs(0);
printf("%lld\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: