A.操作序列
题意:见题面
题解:纯模拟题,注意map.lower_bound(key)恰好是我们所需要的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
map<int,int>mp;
int main()
{
int n,t,c;
scanf("%d",&n);
while(n--)
{
scanf("%d",&t);
if(getchar()=='\n')
{
if(t==-1)
{
if(mp.empty())puts("skipped");
else
{
printf("%d\n",mp.begin()->second);
mp.erase(mp.begin());
}
}
else
{
if(mp.count(t))
printf("%d\n",mp[t]);
else
puts("0");
}
}
else
{
scanf("%d",&c);
auto it = mp.lower_bound(t-30);
if(it==mp.end()||it->first>t+30)
mp[t]+=c;
}
}
return 0;
}
B.树上子链
题意:给定权值,求一棵树的直径
题解:很常规的一道题目了,树形dp即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
ll p[maxn], dp[maxn], res = -INF;
vector<int> G[maxn];
void dfs(int u, int f)
{
dp[u] = p[u];
for (auto v : G[u])
{
if (v == f)
continue;
dfs(v, u);
res = max(res, dp[u] + dp[v]);
dp[u] = max(dp[u], dp[v] + p[u]);
}
res = max(res, dp[u]);
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &p[i]);
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
printf("%lld\n", res);
return 0;
}
C.交换游戏
题意:见题面
题解:一道搜索题,dfs+记忆化搜索
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3fLL;
map<int, int> vis;
int dfs(int x)
{
if (!x || vis[x])
return vis[x];
for (int i = 0; i < 12; i++)
if (x & 1 << i)
vis[x]++;
for (int i = 0; i < 10; i++)
if (x >> i + 1 & 1 && (x >> i & 1) ^ (x >> i + 2 & 1))
vis[x] = min(vis[x], dfs(x ^ 7 << i));
return vis[x];
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
{
char s[15];
scanf("%s", s);
int x = 0;
for (int i = 0; i < 12; i++)
if (s[i] == 'o')
x += 1 << i;
printf("%d\n", dfs(x));
}
return 0;
}
D.收集纸片
题意:一个点是起点也是终点,中间需要经过n个点,问最少走多少路。
题解:发现n只有10,枚举所有顺序即可,可以用字典序排序来做。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
pair<int,int>p[20];
int s[20];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,n1;
scanf("%d%d",&n,&m);
scanf("%d%d",&p[0].first,&p[0].second);
scanf("%d",&n1);
for(int i=1;i<=n1;i++)
scanf("%d%d",&p[i].first,&p[i].second);
for(int i=1;i<=n1;i++)
s[i]=i;
p[n1+1].first=p[0].first;
p[n1+1].second=p[0].second;
int res = INF;
do{
int tmp=0;
for(int i=1;i<=n1+1;i++)
tmp+=abs(p[s[i]].first-p[s[i-1]].first)+abs(p[s[i]].second-p[s[i-1]].second);
res = min(res,tmp);
}while(next_permutation(s+1,s+n1+1));
printf("The shortest path has length %d\n",res);
}
return 0;
}
E.方块涂色
题意:见题面
题解:将涂色的行列分别移到最上边和最左边,求右下角的面积即可。或者直接容斥定理
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int main()
{
ll n,m,r,c;
while(scanf("%lld%lld%lld%lld",&n,&m,&r,&c)!=EOF)
printf("%lld\n",(n-r)*(m-c));
return 0;
}
F.累乘数字
题意:见题面
题解:乘d次100就打2d个0即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int main()
{
int n,d;
while(scanf("%d%d",&n,&d)!=EOF)
{
printf("%d",n);
for(int i=0;i<d;i++)
printf("00");
puts("");
}
return 0;
}
G.仓库选址
题意:在图中选一个点使全图加权距离最小。
题解:可以分别求出x和y的贡献,对于每个点的贡献就是x的贡献和加上y的贡献和,取最小即可。或者可以二位前缀和来维护每一个点的贡献。这题的数据挺水的,暴力也能过。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3fLL;
int x[maxn], y[maxn];
ll sumx[maxn], sumy[maxn];
int a[maxn][maxn];
void init()
{
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
memset(sumx, 0, sizeof(sumx));
memset(sumy, 0, sizeof(sumy));
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, m;
scanf("%d%d", &m, &n);
init();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
x[i] += a[i][j];
y[j] += a[i][j];
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
sumx[i] += 1ll * abs(i - j) * x[j];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
sumy[i] += 1ll * abs(i - j) * y[j];
ll res = INFL;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
res = min(res, sumx[i] + sumy[j]);
printf("%lld\n", res);
}
return 0;
}
H.货物种类
题意:见题面
题解:对于不带修改的单点求和,差分算是一种比较好写的做法了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3fLL;
map<int, int> b[maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
int l, r, d;
scanf("%d%d%d", &l, &r, &d);
b[l][d]++;
b[r + 1][d]--;
}
map<int, int> now;
int res, cnt = 0;
for (int i = 1; i <= n; i++)
{
for (auto it : b[i])
{
now[it.first] += it.second;
if (now[it.first] == 0)
now.erase(it.first);
}
if (now.size() > cnt)
{
cnt = now.size();
res = i;
}
}
printf("%d\n", res);
return 0;
}
I.工具人
J.计算A+B
题意:见题面
题解:是一道水题,但是用C写码量挺大的,用Python写就很简单
t = int(input())
for i in range(t):
n = input().split("+")
if len(n) != 2 or n[0] == '' or n[1] == '':
print("skipped")
else:
print(int(n[0]) + int(n[1]))