队友写了题,好评如潮
A
来自zkp同学
#include<iostream>
#include<map>
using namespace std;
int main()
{
int n;
string a,b;
map<char,char>mp;
cin>>n;
for(int k=1;k<=n;k++)
{
cin>>a>>b;
for(int i=0;i<26;i++)mp[i+'a']=b[i];
int z,x,c,v;
z=x=c=v=0;
for(int i=0;i<a.size();i++)
{
char f=mp[a[i]];
if(f=='d')z++,v++;
if(f=='w')x++,v++;
if(f=='h')c++,v++;
}
cout<<"Case #"<<k<<": ";
if(c*4>=v)cout<<"Harmful\n";
else if(c*10<=v)cout<<"Recyclable\n";
else if(z>=x*2)cout<<"Dry\n";
else cout<<"Wet\n";
}
}
B
来自小洛洛,每次直接替换掉一整段0,然后string暴力比较一下大小即可
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <array>
#include <cstdint>
#include <sstream>
std::string fmt_v6 (const std::string &bin) {
auto dig = std::array<uint16_t, 8> {};
for (int i = 0; i < 128; ++i)
dig[i / 16] = dig[i / 16] * 2 + (bin[i] - '0');
auto mxlen = std::array<int, 8> {};
int mx = 0;
for (int i = 0; i < 8; ++i) {
if (dig[i] == 0)
mxlen[i] = 1 + (i == 0 ? 0 : mxlen[i - 1]);
else
mxlen[i] = 0;
mx = std::max(mx, mxlen[i]);
}
if (mx == 8)
return "::";
auto gen = [&](int l, int r) {
auto ss = std::ostringstream();
for (int i = 0; i < 8; ++i)
if (i == l) {
i = r - 1;
ss << "::";
} else {
if (i != 0 && i != r)
ss << ":";
ss << std::hex << dig[i];
}
return ss.str();
};
if (mx <= 1)
return gen(-1, -1);
std::string ret;
for (int i = 0; i < 8; ++i)
if (mxlen[i] == mx) {
auto cur = gen(i - mxlen[i] + 1, i + 1);
if (ret.length() == 0
|| cur.length() < ret.length()
|| (cur.length() == ret.length() && cur < ret))
ret = cur;
}
return ret;
}
int main () {
std::ios::sync_with_stdio(false);
int n;
std::cin >> n;
for (int i = 1; i <= n; ++i) {
std::string s;
std::cin >> s;
auto ans = fmt_v6(s);
std::cout << "Case #" << i << ": " << ans << "\n";
}
return 0;
}
C
这题没有意识到所有的回文子串其实就是所有的祖先们的fail,举个栗子,就是bcaabaacb,祖先有caabaac,aabaa,aba,b,这些里面所有的fail加在一起就是这个回文子串的所有回文子串。
那么我们只要dfs的时候,每次暴力往上打标记,因为每次增加2个字母,最多增加两个回文子串,也就是每次打标记最多增加两个回文子串,那么复杂度就是
O
(
n
)
O(n)
O(n)了。
考虑在父亲处累加,也就是所有的子树大小乘上自己打的标记数量(每个标记对于子树里的都有贡献)。
/* ***********************************************
Author :BPM136
Created Time :2019/8/4 11:14:49
File Name :C.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
struct PalindromicTree {
static int const N = 200005;
int nxt[N][26];
int fail[N];
int len[N]; //该节点表示的回文子串的长度
int s[N], L, R; /表示要插入的字符串
int cont[N]; /表示这个节点对于回文子串总数的贡献,如果在线询问总数就用这个算就好了,因为要加1的节点一定是这个节点跳fail到根路径上的所有节点,那么也就是cont[fail] + 1
int cnt[N]; //表示这个节点表示的回文串的个数,最后需要count函数计数才行
int last[2]; 0表示左边插入的last,1表示右边插入的last
int p; ///节点数目 p - 2 就是本质不同的回文串个数(除掉表示偶数长度和奇数长度的树根)
ll sum; ///整个串回文子串的个数(包括不同位置出现的同样的回文子串)
int sz[N], c[N];
int vis[N];
int newNode(int _len) {
for(int i = 0; i < 26; ++i)
nxt[p][i] = 0;
cont[p] = 0;
len[p] = _len;
return p++;
}
void init(int n) { ///n表示这个字符串的最长长度
p = 0;
newNode(0);
newNode(-1);
std::fill(std::begin(s), std::end(s), -1);
std::fill(std::begin(cnt), std::end(cnt), 0);
L = n;
R = n - 1;
last[0] = last[1] = 1;
fail[0] = 1;
sum = 0;
}
int getFail(int v, bool ty) {
int bord = ty == 1 ? R : L;
int cons = ty == 1 ? -1 : 1;
while(s[bord + cons * (len[v] + 1)] != s[bord])
v = fail[v];
return v ;
}
void add(int c, bool ty) {
if(ty)
s[++R] = c;
else
s[--L] = c;
int cur = getFail(last[ty], ty);
if(nxt[cur][c] == 0) {
int now = newNode(len[cur] + 2);
fail[now] = nxt[getFail(fail[cur], ty)][c];
nxt[cur][c] = now;
cont[now] = cont[fail[now]] + 1;
///要维护新的东西就从cur转移来就好了
}
last[ty] = nxt[cur][c];
if(len[last[ty]] == R - L + 1)
last[ty ^ 1] = last[ty];
sum += cont[last[ty]];
++cnt[last[ty]];
}
void count() {
for(int i = p - 1; i > 1; --i) 0和1为偶数长度和奇数长度的根节点,所以不能计数
cnt[fail[i]] += cnt[i];
}
int dfs(int x) {
sz[x] = 1;
c[x] = 0;
for (int y = x; y >= 2 && vis[y] == 0; y = fail[y]) {
++c[x];
vis[y] = x;
}
for (int i = 0; i < 26; ++i)
if (nxt[x][i])
sz[x] += dfs(nxt[x][i]);
for (int y = x; y >= 2 && vis[y] == x; y = fail[y])
vis[y] = 0;
return sz[x];
}
ll solve() {
ll ret = 0;
dfs(0);
dfs(1);
for (int i = 2; i < p; ++i)
ret += 1LL * sz[i] * c[i];
return ret - p + 2;
}
}tree;
int main() {
USE_CIN_COUT;
int T;
cin >> T;
string s;
for (int o = 1; o <= T; ++o) {
cin >> s;
tree.init(SZ(s));
for (auto c : s)
tree.add(c - 'a', 0);
ll ans = tree.solve();
cout << "Case #" << o << ": " << ans << '\n';
}
return 0;
}
D
二分答案就行,不过要注意到答案并不单调,但是每次的不单调区间不超过maxV,而且并不大,那么暴力调参就调过去了x
其实枚举一下上下界也是一样的
#include <iostream>
#include <numeric>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <array>
#include <cstdint>
#include <set>
int check (std::vector<int> const &v, int cap) {
auto s = std::multiset<int>(std::begin(v), std::end(v));
int cnt = 0;
while (!s.empty()) {
int rest = cap;
++cnt;
for (;;) {
auto it = s.upper_bound(rest);
if (it == s.begin())
break;
--it;
rest -= *it;
s.erase(it);
}
}
return cnt;
}
// (ERROR * log2(sum{v} / WINDOW) + WINDOW) * n log n
int solve (std::vector<int> const &v, int k) {
int l = *std::max_element(std::begin(v), std::end(v));
int r = std::accumulate(std::begin(v), std::end(v), 0);
if (k == 1)
return r;
if (check(v, l) <= k)
return l;
const int WINDOW = 100;
const int ERROR = 30;
while (r - l > WINDOW) {
int m = l + (r - l) / 2;
int m1 = m - ERROR, m2 = m + ERROR;
bool ok = false;
for (int i = m1; i < m2; ++i)
if (check(v, i) <= k) { // Already ok.
ok = true;
r = i;
break;
}
if (!ok)
l = m2;
}
while (l < r && check(v, l) > k) // until <= k
++l;
return l;
}
int main () {
std::ios::sync_with_stdio(false);
// int n;
// std::cin >> n;
// auto v = std::vector<int>(n);
// for (auto &c: v)
// std::cin >> c;
// int mx = *std::max_element(std::begin(v), std::end(v));
// for (int i = mx; i <= mx + 30; ++i)
// std::cout << i << "\t" << check(v, i) << "\n";
int t;
std::cin >> t;
for (int i = 1; i <= t; ++i) {
int n, k;
std::cin >> n >> k;
auto v = std::vector<int>(n);
for (auto &c: v)
std::cin >> c;
auto ans = solve(v, k);
std::cout << "Case #" << i << ": " << ans << "\n";
}
return 0;
}
E
提供两个代码,一个是我和zkp写的,一个是小洛洛的
首先自补图存在的充要条件是n为4k或者4k+1,只要发现自己和补图加在一起是一个完全图,而且边数相同,那么这个完全图的边数一定是偶数。充分性的证明用度数序列构造一下就行。
那么就是考虑构造了,如果是4k,由可图性的定理,首先分成2份,每份2k个点。
然后度数序列
3
k
−
1
,
3
k
−
1
,
3
k
−
1
,
.
.
.
,
k
,
k
,
k
,
.
.
.
3k-1,3k-1,3k-1,...,k,k,k,...
3k−1,3k−1,3k−1,...,k,k,k,...一定是可图的。
这个度数序列对应的图的样子就是,首先把前面的2k个点连成完全图,然后后面的2k个点围成一圈,往对应的连续的k个点连起来。
如果是4k+1,那么多建一个度数为一半的点就行
最后是我写了4k的部分,zkp写了4k+1的部分
后来小洛洛补了一个不断加点的代码
这是小洛洛的代码
#include <iostream>
#include <numeric>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <array>
#include <cstdint>
#include <set>
using Mat = std::vector<std::vector<char>>;
using Ans = std::pair<Mat, std::vector<int>>;
Ans gen_ans (int n) {
return { Mat(n, std::vector<char>(n, 0)), std::vector<int>(n) };
}
Ans solve (int n) {
auto ans = gen_ans(n);
auto set = [&](int i, int j) {
ans.first[i][j] = ans.first[j][i] = 1;
};
for (int i = 0; i < n / 2; ++i)
for (int j = i + 1; j < n / 2; ++j)
set(i, j);
for (int i = 0; i < n / 2; ++i)
for (int j = 0; j < n / 4; ++j)
set(n / 2 + i, (i + j) % (n / 2));
for (int i = 0; i < n / 2; ++i)
// ans.second[i] = n / 2 + i;
ans.second[n / 2 + i] = i;
for (int i = 0; i < n / 2; ++i)
// ans.second[n / 2 + i] = (-1 + i + n / 2) % (n / 2);
ans.second[(-1 + i + n / 2) % (n / 2)] = n / 2 + i;
if (n & 1) {
for (int i = 0; i < n / 2; ++i)
set(n - 1, i);
ans.second[n - 1] = n - 1;
}
return ans;
}
int main () {
std::ios::sync_with_stdio(false);
int t;
std::cin >> t;
for (int i = 1; i <= t; ++i) {
int n;
std::cin >> n;
std::cout << "Case #" << i << ": ";
if (n % 4 >= 2) {
std::cout << "No\n";
continue;
}
Ans ans = solve(n);
std::cout << "Yes\n";
for (int i = 0; i < n; ++i, std::cout << '\n')
for (int j = 0; j < n; ++j)
std::cout << (int)ans.first[i][j];
for (int i = 0; i < n; ++i) {
std::cout << ans.second[i] + 1;
std::cout << (i == n - 1 ? '\n' : ' ');
}
}
return 0;
}
这是我和zkp的组合代码
/* ***********************************************
Author :BPM136
Created Time :2019/8/3 16:26:39
File Name :E.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
void solve4n(int sum) {
static bool w[2001][2001];
static int f[2001];
for (int i = 1; i <= sum; ++i)
for (int j = 1; j <= sum; ++j)
w[i][j] = 0;
int n = sum / 4;
memset(w, 0, sizeof(w));
for (int i = 1; i <= n * 2; ++i)
for (int j = 1; j <= n * 2; ++j)
w[i][j] = i != j;
for (int i = 1; i <= n * 2; ++i) {
int now = 2 * n + i, p = i;
for (int j = 1; j <= n; ++j) {
w[now][p] = w[p][now] = 1;
++p;
if (p > 2 * n)
p -= 2 * n;
}
}
for (int i = 1; i <= sum; ++i) {
for (int j = 1; j <= sum; ++j)
cout << w[i][j];
cout << '\n';
}
for (int i = 1; i <= n; ++i)
f[i] = 2 * n + i;
for (int i = 1; i <= n; ++i)
f[i + n] = 3 * n + i;
int p = n * 2;
for (int i = 1; i <= n; ++i) {
f[i + n * 2] = p;
++p;
if (p >= 2 * n)
p -= 2 * n;
}
for (int i = 1; i <= n; ++i) {
f[i + n * 3] = p;
++p;
if (p >= 2 * n)
p -= n * 2;
}
cout << f[1];
for (int i = 2; i <= sum; ++i)
cout << ' ' << f[i];
cout << '\n';
}
void solve4n_1(int n) {
static bool map[2001][2001];
static int f[2001];
for(int i=0;i<n;i++)for(int j=0;j<n;j++)map[i][j]=0;
int r = n / 2;
for(int i=0;i<r;i++)for(int j=i+1;j<r;j++)map[i][j]=map[j][i]=1;
for(int i=0;i<r;i++)map[i][r]=map[r][i]=1;
for(int i=0;i<r;i++)for(int j=0;j<r/2;j++)
{
map[i][(j+i)%r+r+1]=map[(j+i)%r+r+1][i]=1;
}
for(int i=1;i<=r;i++)f[i]=i+r+1;
f[r+1]=r+1;
for(int i=1;i<=r;i++)f[i+r+1]=(i)%r+1;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++)
cout<<map[i][j];
cout << '\n';
}
cout << f[1];
for(int i=2;i<=n;i++)
cout<<' '<<f[i];
cout << '\n';
}
int main() {
USE_CIN_COUT;
int T;
cin >> T;
for (int o = 1; o <= T; ++o) {
int n;
cin >> n;
cout << "Case #" << o << ": ";
if (n % 4 == 0) {
cout << "Yes" << '\n';
solve4n(n);
continue;
}
if (n % 4 == 1) {
cout << "Yes" << '\n';
solve4n_1(n);
continue;
}
cout << "No" << '\n';
}
return 0;
}
F
G
了解了蔡勒公式和基姆拉尔森计算公式。就是给你一个日期,算这是星期几,不得不说后者好用的多。
然后接下来爆搜就可以了,不过要注意去重和2月29日.
/* ***********************************************
Author :BPM136
Created Time :2019/8/4 17:59:43
File Name :G.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int sum_d[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int getNum(string s, vector<int> const& f) {
int ret = 0;
for (auto const& c : s)
ret = ret * 10 + f[c - 'A'];
return ret;
}
bool chk(int y, int m, int d) {
if (y < 1600 || m <= 0 || m > 12 || d <= 0)
return 0;
int lim = sum_d[m];
if (m == 2 && ((y % 4 == 0 && y % 100) || y % 400 == 0))
++lim;
if (d > lim)
return 0;
if (m == 1 || m == 2)
m += 12, --y;
auto w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7;//此为其他公式,直接输出w即可
return (w + 7) % 7 == 5;
}
int main() {
USE_CIN_COUT;
int T;
cin >> T;
for (int o = 1; o <= T; ++o) {
int n;
cin >> n;
auto f = vector<int>(10);
for (int i = 0; i < 10; ++i)
f[i] = i;
auto a = vector<string>(n);
for (auto& v : a)
cin >> v;
sort(all(a));
a.erase(unique(all(a)), a.end());
cout << "Case #" << o << ": ";
bool ans = 0;
do {
bool can = 1;
for (auto const& v : a) {
int yy = getNum(v.substr(0, 4), f);
int mm = getNum(v.substr(5, 2), f);
int dd = getNum(v.substr(8, 2), f);
if (chk(yy, mm, dd) == 0) {
can = 0;
break;
}
}
if (can) {
for (auto v : f)
cout << v;
cout << '\n';
ans = 1;
break;
}
} while (next_permutation(all(f)));
if (ans == 0)
cout << "Impossible" << '\n';
}
return 0;
}
H
I
J
贪心即可。
每次枚举最低的等级,维护最大的前缀和,如果有物品的最大的前缀和就是当前的等级,那么就直接更新ans,否则枚举一下是谁被一定要求是当前等级即可
/* ***********************************************
Author :BPM136
Created Time :2019/8/3 12:51:28
File Name :J.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
int const N = 1005;
pli mx[N];
int c[N][N], d[N];
ll sum[N][N];
ll sum_d[N];
int n, m;
void Remax(pli& t, ll val, int pos) {
if (val == t.first)
t.second = pos;
if (val > t.first)
t = make_pair(val, pos);
}
int main() {
USE_CIN_COUT;
int T;
cin >> T;
for (int o = 1; o <= T; ++o) {
cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
cin >> c[i][j];
c[i][j] = -c[i][j];
sum[i][j] = sum[i][j - 1] + c[i][j];
}
for (int j = 1; j <= m; ++j) {
cin >> d[j];
sum_d[j] = sum_d[j - 1] + d[j];
}
for (int i = 1; i <= n; ++i)
mx[i] = make_pair(-1e9 * 1000, -1);
ll ans = 0;
for (int i = m; i >= 0; --i) {
ll anss = sum_d[i], sumc = 0;
bool flag = 0;
for (int j = 1; j <= n; ++j) {
Remax(mx[j], sum[j][i], i);
sumc += mx[j].first - sum[j][i];
anss += sum[j][i];
if (mx[j].second == i)
flag = 1;
}
assert(sumc >= 0);
if (flag)
ans = max(ans, anss + sumc);
else {
for (int j = 1; j <= n; ++j)
ans = max(ans, anss + sumc - mx[j].first + sum[j][i]);
}
}
cout << "Case #" << o << ": " << ans << '\n';
}
return 0;
}