A. Transformation: from A to B
一个数a,两种操作,一是把a*2,二是把a*10+1,问把a变到b是否有解和最小次数。
两种操作都是指数级别的,爆搜即可。
//
// main.cpp
// 727A
//
// Created by 翅膀 on 16/10/21.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
map pre;
void bfs(ll a, ll b) {
queue q;
q.push(a); pre[a] = -1;
while(!q.empty()) {
ll u = q.front(); q.pop();
if(u == b) return;
ll v1 = u*2;
if(v1 <= b && pre.find(v1) == pre.end()) {
q.push(v1); pre[v1] = u;
}
ll v2 = u*10+1;
if(v2 <= b && pre.find(v2) == pre.end()) {
q.push(v2); pre[v2] = u;
}
}
}
int main(int argc, const char * argv[]) {
ll a, b;
cin >> a >> b;
bfs(a, b);
if(pre.find(b) == pre.end()) return 0*puts("NO");
stack ans;
while(b != -1) {
ans.push(b);
b = pre[b];
}
puts("YES");
printf("%lld\n", (ll)ans.size());
while(!ans.empty()) {
printf("%lld ", ans.top()); ans.pop();
}
return 0;
}
B. Bill Total Value
给一串字符串,分析里面的数字出来求和,数字是每三位有逗号,如果有小数则固定是三位小数。
按题意模拟即可,码力和提交次数成反比。
//
// main.cpp
// 727B
//
// Created by 翅膀 on 16/10/25.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
#include
#include
using namespace std;
string s;
vector<string>ss;
double check(const string& x) {
double res = 0;
if(x.size() < 3) {
for(char c : x) {
res = res*10+(int)c-'0';
}
return res;
}
if(x[x.size()-3] == '.') {
for(int i = 0; i < x.size()-3; ++i) {
if(x[i] == '.') continue;
res = res*10+(int)x[i]-'0';
}
res += ((int)x[x.size()-2]-'0')/10.0;
res += ((int)x[x.size()-1]-'0')/100.0;
return res;
}
else {
for(int i = 0; i < x.size(); ++i) {
if(x[i] == '.') continue;
res = res*10+(int)x[i]-'0';
}
return res;
}
}
int main(int argc, const char * argv[]) {
cin >> s;
for(int i = 0; i < s.size(); ++i) {
if(s[i] >= '0' && s[i] <= '9') {
for(int j = i; j < s.size(); ++j) {
if(j == s.size()-1) {
ss.emplace_back(s.substr(i, j-i+1));
i = j;
continue;
}
if(s[j] >= 'a' && s[j] <= 'z') {
ss.emplace_back(s.substr(i, j-i));
i = j-1;
break;
}
}
}
}
double ans = 0;
for(auto& x : ss) {
ans += check(x);
}
char sans[5000];
sprintf(sans, "%.2f", ans);
int len = (int)strlen(sans);
int cnt = (len-3)%3;
if(cnt == 0) cnt = 3;
for(int i = 0; i < cnt; ++i) putchar(sans[i]);
for(int i = cnt; i < len-3; i += 3) {
if(cnt) putchar('.');
putchar(sans[i]); putchar(sans[i+1]); putchar(sans[i+2]);
}
if(sans[len-1] != '0' || sans[len-2] != '0') {
putchar('.');
putchar(sans[len-2]);
putchar(sans[len-1]);
}
puts("");
return 0;
}
C. Guess the Array
交互题,数据是一个数组,你知道数组长度是n,然后你可以询问n次,每次询问任意ai+aj的和,输出整个数组。
先问a1+a2,a2+a3,a3+a1,然后就可以解出a1,a2,a3,后面的就直接出来了。
//
// main.cpp
// 727C
//
// Created by 翅膀 on 16/10/21.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
using namespace std;
int query(int i, int j) {
printf("? %d %d\n", i, j);
fflush(stdout);
int res = 0;
scanf("%d", &res);
return res;
}
int a[5005];
int main(int argc, const char * argv[]) {
int n;
scanf("%d", &n);
int a12 = query(1, 2);
int a23 = query(2, 3);
int a13 = query(1, 3);
a[1] = (a13+a12-a23)/2;
a[2] = a12-a[1];
a[3] = a13-a[1];
for(int i = 4; i <= n; ++i) {
a[i] = query(1, i)-a[1];
}
printf("!");
for(int i = 1; i <= n; ++i) {
printf(" %d", a[i]);
}
puts("");
fflush(stdout);
return 0;
}
D. T-shirts Distribution
6种大小的衣服,各有若干件,然后每个人有1种或2种选择,每个人得到的衣服大小必须是他们选的,问有没有这种分配方案,可以就输出一种方案。
第一反应网络流,然后每个大小建一个点,每个人建一个点,按他们的选择连边,最后跑完最大流看是不是满流,然后根据流向输出方案。
//
// main.cpp
// 727D
//
// Created by 翅膀 on 16/10/21.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 150005;
const int M = 300005;
const int inf = ~0u>>2;
struct eg{
int u, v, cap; //源点汇点流量
eg(){}
eg(int a, int b, int c){ u = a, v = b, cap = c; }
}edg[M*4]; //边数开大
int fir[N], nex[M*4], ecnt, s, t;
void add(int a, int b, int c){
edg[ecnt] = eg(a, b, c);
nex[ecnt] = fir[a], fir[a] = ecnt++;
edg[ecnt] = eg(b, a, 0); //反向边
nex[ecnt] = fir[b], fir[b] = ecnt++;
}
int lev[N], q[N*4], top, tail;
bool Bfs(int s, int t){
memset(lev, -1, sizeof(lev));
top = tail = 0;
lev[s] = 0; q[tail++] = s;
while( top < tail ){
int u = q[top++];
if( u == t ) return 1;
for(int k = fir[u]; k != -1; k = nex[k]){
int v = edg[k].v;
if( edg[k].cap && lev[v] == -1){
lev[v] = lev[u] + 1;
q[tail++] = v;
}
}
}
return 0;
}
int Dfs(int s, int t, int low){
if( s == t ) return low;
int a = 0, res = 0;
for(int k = fir[s]; k != -1; k = nex[k]){
int v = edg[k].v;
if(edg[k].cap && lev[v] == lev[s] +1 ){
a = Dfs(v, t, min(low - res, edg[k].cap) );
edg[k].cap -= a;
edg[k^1].cap += a;
res += a;
if(res == low) return res;
}
}
if(res == 0) lev[s] = -1;
return res;
}
int Dinic(int s, int t){
int res = 0, minflow;
while( Bfs(s, t) ){
while( (minflow = Dfs(s, t, inf)) ) res += minflow;
}
return res;
}
int a[10];
char str[100];
inline int chos(const char& a, const char& b, const char& c) {
if(a == 'S') return 1;
else if(a == 'M') return 2;
else if(a == 'L') return 3;
else if(c == 'X') return 6;
else if(b == 'X') return 5;
else if(a == 'X') return 4;
exit(-1);
}
int ans[100005];
inline void print(const int &i) {
if(i == 1) puts("S");
else if(i == 2) puts("M");
else if(i == 3) puts("L");
else if(i == 4) puts("XL");
else if(i == 5) puts("XXL");
else if(i == 6) puts("XXXL");
}
// 1~6 S~XXXL 7~12
vector<int>cnt[100];
int main(int argc, const char * argv[]) {
memset(fir, -1, sizeof(fir));
ecnt = 0;
for(int i = 1; i <= 6; ++i){
scanf("%d", a+i);
}
int q, sub = 0;
scanf("%d", &q);
s = 0, t = 100;
for(int k = 7; k <= q+6; ++k) {
memset(str, 0, sizeof(char)*10);
scanf("%s", str);
int pos = -1;
for(int i = 0; str[i]; ++i) {
if(str[i] == ',') {
pos = i;
break;
}
}
if(pos == -1) {
int tmp = chos(str[0], str[1], str[2]);
if(a[tmp] == 0) return 0*puts("NO");
a[tmp]--;
ans[k] = tmp;
sub++;
}
else {
int a = chos(str[0], str[1], str[2]);
int b = chos(str[pos+1], str[pos+2], str[pos+3]);
cnt[a*6+b].push_back(k);
}
}
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j) {
if(i == j) continue;
add(i, i*6+j, a[i]);
add(j, i*6+j, a[j]);
add(i*6+j, t, (int)cnt[i*6+j].size());
}
add(s, i, a[i]);
}
for(int i = 1; i <= 6; ++i) add(s, i, a[i]);
if(ecnt > M*4 || t > N) return -1;
int maxflow = sub+Dinic(s, t);
if(maxflow != q) return 0*puts("NO");
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j) {
for(int k = fir[i*6+j]; k != -1; k = nex[k]) {
int v = edg[k].v;
if(edg[k].cap && v <= 6 && v >= 1) {
for(int l = 0; l < edg[k].cap; ++l) {
if(cnt[i*6+j].empty()) return 0*puts("NO");
ans[cnt[i*6+j].back()] = v;
if(a[v] == 0) return 0*puts("NO");
a[v]--;
cnt[i*6+j].pop_back();
}
}
}
}
}
puts("YES");
for(int i = 6; i <= q+6; ++i) {
print(ans[i]);
}
return 0;
}
E. Games on a CD
一个串长度为n*k,然后把它首尾接起来,再给你g(>=n)个长度为k的串,问你用这g个串能不能组成原来的串。
先把原串加倍,因为是环,所以枚举起点(最多k次)检查是不是可以组成。
我的做法是多项式hash,这样可以快速得到任意一段的hash值,g个串也hash,然后暴力匹配。推荐双hash,毕竟cf。
检查最多n次,枚举k次,总复杂度是O(n*k)的,先看出这个复杂度那就比较好做了。
//
// main.cpp
// 727E
//
// Created by 翅膀 on 16/10/22.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
typedef pair pii;
const ull mod1 = 982886081;
const ull mod2 = 889930273;
const ull s1 = 131;
const int N = 2e6+5;
ull pm1[N], pm2[N];
pii strhash[N];
void init(char *s, int len) {
pm1[0] = pm2[0] = 1;
for(int i = 1; i < N; ++i) {
pm1[i] = pm1[i-1]*s1%mod1;
pm2[i] = pm2[i-1]*s1%mod2;
}
strhash[0] = pii(s[0]*pm1[0], s[0]*pm2[0]);
for(int i = 1; i < len; ++i) {
strhash[i] = pii((strhash[i-1].first+s[i]*pm1[i])%mod1, (strhash[i-1].second+s[i]*pm2[i])%mod2);
}
}
ull qpow(ull a, ull k, const ull& mod) {
ull res = 1;
while(k) {
if(k&1) res = res*a%mod;
a = a*a%mod;
k >>= 1;
}
return res;
}
pii shash(int l, int r) {
if(l == 0) return strhash[r];
ull one = strhash[r].first;
one = (one-strhash[l-1].first+mod1)%mod1;
one = one*qpow(pm1[l], mod1-2, mod1)%mod1;
ull two = strhash[r].second;
two = (two-strhash[l-1].second+mod2)%mod2;
two = two*qpow(pm2[l], mod2-2, mod2)%mod2;
return make_pair(one, two);
}
pii ghash(char *s, int k) {
ull r1 = 0, r2 = 0;
for(int i = 0; i < k; ++i) {
r1 = (r1+s[i]*pm1[i])%mod1;
r2 = (r2+s[i]*pm2[i])%mod2;
}
return pii(r1, r2);
}
mapint >mp;
bool used[N];
char s[N];
ull sh[N];
int main(int argc, const char * argv[]) {
int n, k;
scanf("%d%d", &n, &k);
scanf("%s", s);
int len = n*k;
for(int i = 0; i < len; ++i) {
s[i+len] = s[i];
}
init(s, len*2);
int q;
scanf("%d", &q);
for(int i = 1; i <= q; ++i) {
scanf("%s", s);
pii res = ghash(s, k);
mp[res] = i;
}
vector<int>ans;
for(int i = 0; i < k; ++i) {
for(int x : ans) used[x] = 0;
ans.clear();
for(int j = 0; j < n; ++j) {
pii tar = shash(i+j*k, i+(j+1)*k-1);
if(mp.find(tar) == mp.end() || used[mp[tar]]) break;
int id = mp[tar];
used[id] = 1;
ans.push_back(id);
if(j == n-1) {
puts("YES");
for(int x : ans) printf("%d ", x);
return 0;
}
}
}
puts("NO");
return 0;
}
F. Polycarp’s problems
n个数的数组a[i],m次询问,每次询问给出一个初始值x,然后x从a[1]累加到a[n],要求过程中x不能为负,问你最少要删除几个数。
考虑单次回答,贪心。当加到a[i]为负了,那么此时必然要删一个数,显然应该删a[1]~a[i]里面最小的没被删过的数,用个优先队列就可以nlogn单次回答,但是暴力被卡掉了。
换种做法,因为n<=750,所以最多有751个答案,而且初始值越大,答案越小,根据这种单调性就可以预处理答案为i时候的最小的初始值,回答的时候就可以直接二分了。
//
// main.cpp
// 727F
//
// Created by 翅膀 on 16/11/4.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 800;
const ll inf = ~0ull>>3;
int n, m;
ll a[N];
ll ans[N];
ll check(ll x) {
if(x < 0) return inf;
int res = 0;
priority_queuevector, greater >st;
for(int i = 1; i <= n; ++i) {
x += a[i];
if(a[i] < 0) st.push(a[i]);
if(x < 0) {
x -= st.top(); st.pop();
res++;
}
}
return res;
}
ll solve(int x) {
ll l = -inf, r = inf, ans = 0;
while(l <= r) {
ll mid = (l+r) >> 1;
if(check(mid) <= x) r = mid-1, ans = mid;
else l = mid+1;
}
if(ans < 0) ans = -inf;
return ans;
}
int main(int argc, const char * argv[]) {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%lld", a+i);
}
int last = 0;
for(int i = 0; i <= n; ++i) {
ans[i] = solve(i);
last = i;
if(ans[i] < 0) break;
}
while(m--) {
ll x;
scanf("%lld", &x);
int l = 0, r = last, aans = 0;
while(l <= r) {
int mid = (l+r) >> 1;
if(ans[mid] <= x) r = mid-1, aans = mid;
else l = mid+1;
}
printf("%d\n", aans);
}
return 0;
}