A.Knight
题目描述 有一张无限大的棋盘,你要将马从(0,0)移到(n,m)。 每一步中,如果马在(x,y),你可以将它移动到(x 1,y 2),(x 1,y-2),(x-1,y 2),(x-1,y-2),(x 2,y 1),(x 2,y-1),(x-2,y 1)或(x-2,y-1)。 你需要最小化移动步数。
输入描述: 第一行一个整数t表示数据组数 (1≤ t≤ 1000)。 每组数据一行两个整数n,m (|n|,|m|≤ 109)。
输出描述: 每组数据输出一行一个整数表示最小步数。
示例1 输入 2 0 4 4 2 输出 2 2
代码语言:javascript复制不妨假设 x>=y>=0。 当 x<=2y 时,定义每一步的冗余值 wi=3-dx-dy,那么∑wi=∑(2-dx)=3 步数-x-y,显然我们只需要最小化冗余值。我们先只用( 2, 1)(若 x 为奇数则 加一步( 1, 2))走到(x,y’),然后通过将( 2, 1)替换为 2 个( 1, 2)使得 0<=y-y’<3。 若 y-y’=0,则冗余值为 0,显然最小。 若 y-y’=1,则将( 1, 2)替换为( 2, 1)和(-1, 2)或将 2 个( 2, 1)替换为 ( 1, 2),( 1, 2),( 2,-1),冗余值为 2,显然最小。(此处需要特判(2,2)) 若 y-y’=2,则加上( 2, 1)和(-2, 1),冗余值为 4,由于不存在冗余值为 1 的步,所以最小。 当 x>2y 时,定义每一步的冗余值 wi=2-dx,那么∑wi=∑(2-dx)=2步数-x, 显然我们只需要最小化冗余值。我们先只使用( 2, 1)走到(2y,y),然后用 ( 2, 1)和( 2,-1)走到(x’,y)使得 0<=x-x’<4。 若 x-x’=0 则冗余值为 0,显然最小。 若 x-x’=1 则将之前的( 2, 1)改为( 1, 2)和( 2,-1),冗余值为 1,显然最 小。(此处需要特判(1,0)) 若 x-x’=2 则加上( 1, 2)和( 1,-2),冗余值为 2,由 x/2 y 的奇偶性可知 最小。 若 x-x’=3 则加上( 2, 1),( 2, 1),(-1,-2),冗余值为 3,由 x/2 y 的奇偶 性可知最小。 时间复杂度 O(t)
#include<bits/stdc .h>
using namespace std;
typedef long long ll;
ll fun(ll x, ll y) {
if (x == 1 && y == 0) {
return 3;
}
if (x == 2 && y == 2) {
return 4;
}
ll delta = x - y;
if (y>delta) {
return delta - 2 * floor(((double)(delta-y)) / 3.0);
}
else {
return delta - 2 * floor(((double)(delta-y)) / 4.0);
}
}
int main()
{
//freopen("in.txt", "r", stdin);
int t;
cin >> t;
while (t--)
{
ll x, y;
cin >> x >> y;
x = abs(x);
y = abs(y);
if (x < y) {
swap(x, y);
}
cout << fun(x, y) << endl;
}
return 0;
}
D. Shopping
题目描述 你要买n件物品,其中有一些是凳子。 商场正在举行促销活动,如果购物车中有至少一个凳子,那么你可以半价购买这个购物车中最贵的一个物品。 你有m辆购物车,请最小化你的花费。
输入描述: 第一行一个整数t表示数据组数 (1 ≤ t ≤ 100)。 每组数据第一行两个整数n,m (1 ≤ n,m ≤ 1000),接下来n行每行两个整数ai,bi,分别表示第i件物品的价格以及它是否是凳子 (1 ≤ ai ≤ 105, 0 ≤ bi ≤ 1)。
输出描述: 每组数据输出一行一个实数表示最小花费,保留一位小数。
示例1
输入 2 5 1 1 0 2 1 3 1 4 0 5 0 5 10 1 0 2 1 3 1 4 0 5 0
输出 12.5 10.5
代码语言:javascript复制显然可以将最贵的 min(m,凳子个数)个物品打折。 时间复杂度 O(tn)
#include <bits/stdc .h>
using namespace std;
int t;
int n,m;
int main(){
//freopen("in.txt", "r", stdin);
scanf("%d", &t);
int a,b;
while(t--){
scanf("%d%d", &n, &m);
vector<int> v;
int cnt = 0;
for(int i = 0; i < n; i){
scanf("%d%d", &a, &b);
if(b == 1) cnt;
v.push_back(a);
}
sort(v.begin(), v.end());
double ans = 0.0;
int sz = v.size();
m = min(m, cnt);
for(int i = sz-1,j=1; i >= 0; --i, j){
if(j <= m) ans = v[i]/2.0;
else ans = v[i];
}
printf("%.1lfn", ans);
}
return 0;
}
H.Travel
题目描述 魔方国有n座城市,编号为。城市之间通过n-1条无向道路连接,形成一个树形结构。 澜澜打算在魔方国进行m次旅游,每次游览至少一座城市。为了方便,每次旅游游览的城市必须是连通的。此外,澜澜希望游览所有城市恰好一次。 澜澜想知道有多少种旅游方案满足条件,两个方案不同当且仅当存在某一次旅游游览了不同的城市。 澜澜不会数数,所以只好让你来帮他数方案。
输入描述: 第一行一个整数t表示数据组数 (1 ≤ t ≤ 100)。 每组数据第一行两个整数n,m ,接下来n-1行每行两个整数ai,bi表示一条道路 (1≤ ai,bi≤ n)。
输出描述: 每组数据输出一行一个整数表示方案数对109 7取模的结果。
示例1
输入 2 3 1 1 2 1 3 3 2 1 2 1 3
输出 1 4
代码语言:javascript复制把树分成 m 个连通块的方案数是 C(n-1,m-1),乘上 m!就行了。 时间复杂度 O(∑n)
#include <bits/stdc .h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 7;
#define MAX_N 100100
LL f[MAX_N];
void init(){
f[0] = f[1] = 1LL;
for(int i = 2; i < MAX_N; i) f[i] = i * f[i - 1] % MOD;
}
LL powN(LL a, LL n){
LL base = a, res = 1LL;
while(n){
if(n & 1) res = res * base % MOD;
base = base * base % MOD;
n >>= 1;
}
return res;
}
LL inv(LL a, LL MOD){
return powN(a, MOD - 2LL);
}
LL C(LL n, LL m){
if(m == 0) return 1;
if(n < 0 || n < m) return 0;
return (f[n] % MOD) * (inv(f[m], MOD) * inv(f[n - m], MOD) % MOD) % MOD;
}
int main(){
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(0); cin.tie(0);
int t,a,b;
LL n,m;
cin >> t;
init();
while(t--){
cin >> n >> m;
for(int i = 0; i < n - 1; i ) cin >> a >> b;
cout << (C(n-1, m-1) * f[m]) % MOD<< endl;
}
return 0;
}
I.Metropolis
题目描述 魔方国有n座城市,编号为。城市之间通过n-1条无向道路连接,形成一个树形结构。 在若干年之后,其中p座城市发展成了大都会,道路的数量也增加到了m条。 大都会之间经常有贸易往来,因此,对于每座大都会,请你求出它到离它最近的其它大都会的距离。
输入描述: 第一行三个整数n,m,p (1 ≤ n,m ≤ 2*105,2 ≤ p ≤ n),第二行p个整数表示大都会的编号 (1≤ xi≤ n)。接下来m行每行三个整数ai,bi,li表示一条连接ai和bi,长度为li的道路 (1 ≤ ai,bi ≤ n,1 ≤ li ≤ 109)。 保证图是连通的。
输出描述: 输出一行p个整数,第i个整数表示xi的答案。 示例1
输入 5 6 3 2 4 5 1 2 4 1 3 1 1 4 1 1 5 4 2 3 1 3 4 3
输出 3 3 5
代码语言:javascript复制把所有大都会设为源点跑多源最短路,记下每个点是由哪个源点扩展的。 如果从源点 i 出发走到了一个由另一个源点 j 扩展到的点 k,那么从 i 出发 经过 k 的最短距离肯定是 dis[i][j],那么就没有必要继续走下去了。所以只要枚 举所有两端由不同源点扩展的边更新答案就行了。 时间复杂度 O((n m)logn)
#include <bits/stdc .h>
using namespace std;
typedef long long LL;
#define MAX_N 200100
const LL INF = 1e15;
struct Edge{int to; LL cost;};
typedef pair<LL, int> P;
int T;
int n,m,k;
int p[MAX_N];
int is[MAX_N];
LL d[MAX_N];
LL ans[MAX_N];
vector<Edge> G[MAX_N];
void dijstra(){
for(int i = 1; i <= n; i) d[i] = INF;
priority_queue<P, vector<P>, greater<P> > que;
for(int i = 1; i <= k; i){
que.push(P(d[p[i]] = 0, p[i]));
}
while(!que.empty()){
P p = que.top(); que.pop();
int v = p.second;
if(p.first > d[v]) continue;
for(int i = 0; i < G[v].size(); i){
Edge e = G[v][i];
if(d[e.to] > d[v] e.cost){
d[e.to] = d[v] e.cost;
is[e.to] = is[v]; // e.to是由v扩展的
que.push(P(d[e.to], e.to));
} else if(is[v] != is[e.to]){ // 不同源点扩展的边
ans[is[v]] = min(ans[is[v]], d[v] d[e.to] e.cost);
ans[is[e.to]] = min(ans[is[e.to]], d[v] d[e.to] e.cost);
}
}
}
}
int main(){
//freopen("in.txt", "r", stdin);
int u,v;
LL c;
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i) G[i].clear();
scanf("%d", &k);
for(int i = 1; i <= k; i){
scanf("%d", &p[i]);
ans[p[i]] = INF;
is[p[i]] = p[i];
}
for(int i = 1; i <= m; i){
scanf("%d%d%lld", &u, &v, &c);
G[u].push_back((Edge){v, c});
G[v].push_back((Edge){u, c});
}
dijstra();
for(int i = 1; i <= k; i){
printf("%lld%c", ans[p[i]], "n "[i < k]);
}
return 0;
}
J. Graph Coloring I
题目描述 修修在黑板上画了一些无向连通图,他发现他可以将这些图的结点用两种颜色染色,满足相邻点不同色。 澜澜不服气,在黑板上画了一个三个点的完全图。修修跟澜澜说,这个图我能找到一个简单奇环。 澜澜又在黑板上画了一个n个点m条边的无向连通图。很可惜这不是一道数数题,修修做不出来了。 澜澜非常得意,作为一位毒瘤出题人,有了好题当然要跟大家分享,于是他把这道题出给你做了。
输入描述: 第一行两个整数n,m (1≤ n,m≤ 3*105),接下来m行每行两个整数ai,bi表示一条边 (1≤ ai,bi≤ n)。 保证图连通,并且不存在重边和自环。 输出描述: 如果你能把图二染色,第一行输出0,第二行输出n个整数表示每个点的颜色 (0≤ xi≤ 1)。如果有多种合法方案,你可以输出任意一种。 如果你能找到一个简单奇环,第一行输出环长k,第二行输出k个整数表示环上结点编号 (1≤ yi≤ n),你需要保证yi和yi 1之间有边,y1和yn之间有边。如果有多种合法方案,你可以输出任意一种。 如果两种情况都是可行的,你只需要输出任意一种。 如果两种情况都是不可行的,请输出一行一个整数-1。
示例1
输入 3 2 1 2 1 3
输出 0 0 1 1
示例2 复制 3 3 1 2 1 3 2 3
输出 3 1 2 3
代码语言:javascript复制判一下是不是二分图就行了。 时间复杂度 O(n m)
#include <bits/stdc .h>
using namespace std;
const int MAX_N = 3*1e5 100;
int color[MAX_N];
vector<int> G[MAX_N];
vector<int> p;
int n,m;
int s,e;
bool dfs(int u, int c){
color[u] = c;
p.push_back(u);
for(int i = 0; i < G[u].size(); i){
int v = G[u][i];
if(color[u] == color[v]) {s = v, e = u;return false;}
if(!color[v]){
if(!dfs(v, 3 - c)) return false;
}
}
p.erase(--p.end());
return true;
}
int main(){
//freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &m);
int u,v;
for(int i = 1; i <= m; i){
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(color, 0, sizeof(color));
if(dfs(1, 1)){
puts("0");
for(int i = 1; i<= n; i){
printf("%d%c", color[i]-1, "n "[i < n]);
}
} else {
int i = -1;
int sz = p.size();
while(p[ i] != s);
printf("%dn", sz - i);
for(;i < sz; i){
printf("%d%c", p[i], "n "[i < sz-1]);
}
}
return 0;
}