今年年初就和深爷策划去打星参加一场ICPC,正好今年5月底公司多送了2天年假,于是找来了还在电科读研的师弟林喵喵,组了一支退役旅游队。chenjb的这套题出得蛮好,总体来说题目难度不大,但很多题目却很有意思。本老年人成为全场最坑,感谢喵喵和深爷不嫌我菜,带我玩。最终我们只通过了7题,果然退役很久之后越来越菜。结果不是很满意吧,但是能再次去打onsite,真的很开心,彷佛又回到了20岁QAQ
A.Chuanpai
分析:水题
#include "bits/stdc++.h"
using namespace std;
int T;
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
while (T--) {
int k;
scanf("%d", &k);
int cnt = 0;
for (int i = 1; i <= k; i++) {
for (int j = i; j <= k; j++) {
if (i + j == k) {
if (i >= 1 && j >= 1 && i <= 6 && j <= 6) cnt++;
}
}
}
printf("%d\n", cnt);
}
return 0;
}
B.Hotpot
分析:
2
n
2n
2n次就会是一个循环,所以只需要模拟
2
n
2n
2n次以内的所有情况即可
#include "bits/stdc++.h"
using namespace std;
const int maxn = 1e5 + 10;
int T, n, k, m, vis[maxn];
pair<int, int> p[maxn];
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
while (T--) {
memset(vis, 0, sizeof(vis));
scanf("%d%d%d", &n, &k, &m);
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
p[i] = make_pair(x, 0);
}
if (m >= 2 * n) {
for (int i = 0; i < 2 * n; i++) {
int a = i % n;
if (vis[p[a].first] == 0)
vis[p[a].first]++;
else {
vis[p[a].first]--;
p[a].second++;
}
}
int tmp = m / (2 * n);
for (int i = 0; i < n; i++) p[i].second *= tmp;
}
int mod = m % (2 * n);
for (int i = 0; i < mod; i++) {
int a = i % n;
if (vis[p[a].first] == 0)
vis[p[a].first]++;
else {
vis[p[a].first]--;
p[a].second++;
}
}
for (int i = 0; i < n; i++) {
if (i == n - 1)
printf("%d\n", p[i].second);
else
printf("%d ", p[i].second);
}
}
return 0;
}
D.Rock Paper Scissors
分析:先手的所有出牌情况都不对胜负产生影响,只有后手影响胜负,所以后手优先考虑会胜利的,再考虑平局的,最后考虑会扣分的
#include "bits/stdc++.h"
using namespace std;
int T;
typedef long long LL;
LL br, bp, bs, dr, dp, ds;
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
while (T--) {
scanf("%lld%lld%lld", &br, &bp, &bs);
scanf("%lld%lld%lld", &dr, &dp, &ds);
LL cnt = 0;
if (br) {
// cout << dp << endl;
if (dp && br) {
LL tmp = min(dp, br);
cnt += tmp;
dp -= tmp;
br -= tmp;
}
// cout << "--->" << br << " " << dp << endl;
if (dr && br) {
LL tmp = min(dr, br);
dr -= tmp;
br -= tmp;
}
if (ds && br) {
LL tmp = min(ds, br);
cnt -= tmp;
br -= tmp;
ds -= tmp;
}
}
if (bp) {
if (ds && bp) {
LL tmp = min(ds, bp);
cnt += tmp;
ds -= tmp;
bp -= tmp;
}
if (dp && bp) {
LL tmp = min(dp, bp);
dp -= tmp;
bp -= tmp;
}
if (dr && bp) {
LL tmp = min(dr, bp);
cnt -= tmp;
dr -= tmp;
bp -= tmp;
}
}
if (bs) {
if (dr && bs) {
LL tmp = min(dr, bs);
cnt += tmp;
dr -= tmp;
bs -= tmp;
}
if (ds && bs) {
LL tmp = min(ds, bs);
ds -= tmp;
bs -= tmp;
}
if (bs && dp) {
LL tmp = min(bs, dp);
cnt -= tmp;
bs -= tmp;
dp -= tmp;
}
}
printf("%lld\n", cnt);
}
return 0;
}
E.Don’t Really Like How The Story Ends
分析:
(
1
)
(1)
(1)如果
v
v
v与
v
+
1
v + 1
v+1 直接相连,则访问搜索
v
+
1
v + 1
v+1
(
2
)
(2)
(2)如果
v
v
v点存在没有访问的相邻节点且
v
v
v点不与
v
+
1
v + 1
v+1点相连,此时必须将
v
+
1
v + 1
v+1 连接到
v
v
v上
(
3
)
(3)
(3)如果
v
v
v点所有相邻节点都被访问了,
v
+
1
v + 1
v+1 可以与
v
v
v相连,也可以和从
1
=
>
v
1 =>v
1=>v中路径上的任意一点相连,路径上的点都在递归栈里面,此时可以让
v
v
v点退栈,一直回到某个满足条件
1
1
1或
2
2
2的节点
(
4
)
(4)
(4)如果第
3
3
3点的点退栈一直到起点1号点都没有直接相连,说明存在不连通部分,此时必须加边,此时再去搜索不连通的部分,一直到全部搜索完
#include "bits/stdc++.h"
using namespace std;
const int maxn=1e5+100;
int n,m,T;
vector<int>g[maxn];
int vis[maxn],nxt,cnt;
void dfs(int u){
nxt++;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(vis[v]) continue;
if(v==nxt){
vis[nxt]=1;
dfs(nxt);
}else{
cnt++;
vis[nxt]=1;
dfs(nxt);
i--;
}
}
if(u==1){
while(nxt<=n){
vis[nxt]=1;
dfs(nxt);
cnt++;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
for(int i=0;i<=n;i++) {
g[i].clear();
vis[i]=0;
}
cnt=0,nxt=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
if(x<y) g[x].push_back(y);
if(y<x) g[y].push_back(x);
}
for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());
vis[1]=1;
dfs(1);
printf("%d\n",cnt);
}
return 0;
}
F.Direction Setting
分析:最小费用流
对于一条边
(
l
,
r
)
( l , r )
(l,r) 要么指向
l
l
l要么指向
r
r
r,对于
l
l
l来说,前
a
i
a_i
ai条指向自己的边对结果贡献为0,只有从第
a
i
+
1
a_i+1
ai+1条开始,每增加
1
1
1条,权值增加
1
1
1,对于每个点来说,一定是先走免费的,再走收费的,其实就是跑一个最小费用流
具体连边为:
把第
i
i
i条边抽象为点
m
i
m_i
mi,往
l
i
l_i
li和
r
i
r_i
ri连边,容量为1,费用为0;源点
s
s
s往
m
i
m_i
mi连,容量为1,费用为0;对于每个点
u
u
u,往汇点连
1
1
1条容量为
a
u
a_u
au,费用为0的,
1
1
1条容量为
I
N
F
INF
INF,费用为
1
1
1的
#include "bits/stdc++.h"
using namespace std;
const int maxn = 3e5 + 100;
const int INF = 0x3f3f3f3f;
int dis[maxn], vis[maxn], flow[maxn], pre[maxn], id[maxn];
int a[maxn], l[maxn], r[maxn];
int n, m, s, t;
struct edge {
int to, nxt, flow, w;
} d[maxn];
int head[maxn], cnt = 1;
void add(int u, int v, int flow, int w) {
d[++cnt] = (edge){v, head[u], flow, w}, head[u] = cnt;
d[++cnt] = (edge){u, head[v], 0, -w}, head[v] = cnt;
}
bool spfa(int s,int t,int mx){
for(int i=0;i<=mx;i++) dis[i]=INF,vis[i]=0;
queue<int>q; q.push(s);
dis[s]=0,flow[s]=INF;
while(q.size()){
int u=q.front(); q.pop();
vis[u]=0;
for(int i=head[u];i;i=d[i].nxt){
int v=d[i].to;
if(d[i].flow&&dis[u]+d[i].w<dis[v]){
dis[v] = dis[u]+d[i].w,pre[v]=i;
flow[v]=min(d[i].flow,flow[u]);
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
return dis[t]!=INF;
}
int Cost_Flow(int s,int t,int mx){
int mincost=0;
while(spfa(s,t,mx)){
mincost+=dis[t]*flow[t];
int x=t,i;
while(x!=s){
i=pre[x];
d[i].flow-=flow[t],d[i^1].flow+=flow[t];
x=d[i^1].to;
}
}
return mincost;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]);
s=0,t=n+m+1;
for(int i=1;i<=m;i++){
add(s,i,1,0);
id[i]=cnt+1;
add(i,m+l[i],1,0);
add(i,m+r[i],1,0);
}
for(int i=1;i<=n;i++){
add(m+i,t,a[i],0);
add(m+i,t,INF,1);
}
printf("%d\n",Cost_Flow(s,t,n+m+1));
for(int i=1;i<=m;i++) printf("%d",d[id[i]].flow==0?1:0);
printf("\n");
cnt =1;
for(int i=0;i<=t;i++) head[i]=0;
}
return 0;
}
H.Nihongo wa Muzukashii Desu
分析:无脑模拟
#include "bits/stdc++.h"
using namespace std;
int T;
map<string, string> mp;
void init() {
mp["imasu"] = "tte";
mp["mimasu"] = "nde";
mp["kimasu"] = "ite";
mp["gimasu"] = "ide";
mp["shimasu"] = "shite";
mp["chimasu"] = "tte";
mp["rimasu"] = "tte";
mp["bimasu"] = "nde";
mp["nimasu"] = "nde";
}
bool check(string a, string b) {
int i = 0, j = a.length() - 1;
// cout << a << " " << endl;
while (i < j) {
swap(a[i], a[j]);
i++, j--;
}
// cout << a << " " << endl;
i = 0;
// cout << b << " " << endl;
int k = b.length() - 1;
while (i < k) {
swap(b[i], b[k]);
i++, k--;
}
// cout << b << " " << endl;
int lena = a.length(), lenb = b.length();
i = 0;
while (i < lena && i < lenb) {
if (a[i] == b[i])
i++;
else
return false;
}
return true;
}
int main() {
// freopen("in.txt", "r", stdin);
init();
cin >> T;
while (T--) {
string s;
cin >> s;
string res = "";
if (check(s, "chimasu")) {
res += s.substr(0, s.length() - 7) + mp["chimasu"];
} else if (check(s, "rimasu")) {
res += s.substr(0, s.length() - 6) + mp["rimasu"];
} else if (check(s, "bimasu")) {
res += s.substr(0, s.length() - 6) + mp["bimasu"];
} else if (check(s, "nimasu")) {
res += s.substr(0, s.length() - 6) + mp["nimasu"];
} else if (check(s, "kimasu")) {
if (s == "ikimasu")
res = "itte";
else
res += s.substr(0, s.length() - 6) + mp["kimasu"];
} else if (check(s, "gimasu")) {
res += s.substr(0, s.length() - 6) + mp["gimasu"];
} else if (check(s, "shimasu")) {
res += s.substr(0, s.length() - 7) + mp["shimasu"];
} else if (check(s, "mimasu")) {
res += s.substr(0, s.length() - 6) + mp["mimasu"];
} else if (check(s, "imasu")) {
res += s.substr(0, s.length() - 5) + mp["imasu"];
} else
res = s;
cout << res << endl;
}
return 0;
}
J - Ants
分析:解题的关键结论在于两只蚂蚁发生碰撞,可以认为直接穿过。在挡板消失之前,每个蚂蚁在每一轮中会移动
2
L
2L
2L的距离,挡板被撞击
n
n
n次。因此只用模拟最后一轮的情况即可。两块挡板都维护一个队列,维护撞到这块挡板的蚂蚁的时间序列,每次在两个队头中选择一个最小值,模拟之后塞进另一个队列即可。
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 2e6 + 100;
const LL L = 1e9 + 1;
int n, d[maxn], t1, t2, h1, h2;
LL a, b, p[maxn], q1[maxn], q2[maxn], ans;
void solve1() {
LL u = q1[++h1];
ans = max(ans, u);
if (a) {
--a;
q2[++t2] = u + L;
}
}
void solve2() {
LL u = q2[++h2];
ans = max(ans, u);
if (b) {
--b;
q1[++t1] = u + L;
}
}
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d%lld%lld", &n, &a, &b);
for (int i = 1; i <= n; i++) scanf("%lld", &p[i]);
for (int i = 1; i <= n; i++) scanf("%d", &d[i]);
LL tmp = min(a, b) / (LL)n;
a -= tmp * n, b -= tmp * n;
LL s = tmp * 2 * L;
for (int i = 1; i <= n; i++)
if (d[i] == 0) q1[++t1] = p[i];
for (int i = n; i >= 1; i--)
if (d[i] == 1) q2[++t2] = L - p[i];
while (h1 < t1 || h2 < t2) {
if (h2 >= t2 || (h1 < t1 && q1[h1] < q2[h2]))
solve1();
else
solve2();
}
printf("%lld\n", s + ans);
return 0;
}
K. K-skip Permutation
分析:按剩余类分组
#include "bits/stdc++.h"
using namespace std;
const int maxn = 1e6 + 100;
int vis[maxn], n, k;
vector<int> vec[maxn];
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
int mod = i % k;
vec[mod].push_back(i);
}
int cnt = 0;
for (int i = 0; i < k; i++) {
for (int j = 0; j < vec[i].size(); j++) {
cnt++;
if (cnt == n)
printf("%d\n", vec[i][j]);
else
printf("%d ", vec[i][j]);
}
}
return 0;
}
L. Spicy Restaurant
分析:令
d
p
(
i
,
j
)
dp(i,j)
dp(i,j)表示距离
i
i
i位置切好等于
j
j
j的最小值,则最多跑
100
100
100遍
B
F
S
BFS
BFS,可以得到最终答案
#include "bits/stdc++.h"
using namespace std;
const int maxn = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int n, m, q, w[maxn], dp[maxn][100 + 10];
vector<int> g[maxn];
void bfs(int num) {
queue<int> que;
for (int i = 1; i <= n; i++)
if (w[i] == num) {
que.push(i);
dp[i][num] = 0;
}
while (!que.empty()) {
int u = que.front();
que.pop();
for (auto v : g[u]) {
if (dp[v][num] != INF) continue;
que.push(v);
dp[v][num] = dp[u][num] + 1;
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 100; j++) dp[i][j] = INF;
}
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
for (int i = 1; i <= 100; i++) bfs(i);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= 100; j++) dp[i][j] = min(dp[i][j], dp[i][j - 1]);
while (q--) {
int p, a;
scanf("%d%d", &p, &a);
printf("%d\n", dp[p][a] == INF ? -1 : dp[p][a]);
}
return 0;
}
M.True Story
分析:只需要看最多有多少个满足的即可
#include "bits/stdc++.h"
using namespace std;
const int maxn = 1e5 + 10;
int n, k, x, p0;
int s[maxn], t[maxn], p[maxn];
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d%d%d%d", &n, &k, &x, &p0);
int ans = p0;
for (int i = 1; i <= n; i++) scanf("%d", &s[i]);
for (int i = 1; i <= k; i++) scanf("%d", &t[i]);
for (int i = 1; i <= k; i++) scanf("%d", &p[i]);
for (int i = 1; i <= k; i++) ans = max(ans, p[i] - t[i]);
int cnt = 0;
for (int i = 1; i <= n; i++) {
int tmp = (x + s[i] - 1) / s[i];
if (tmp <= ans) cnt++;
}
printf("%d\n", cnt);
return 0;
}