A. Rudolph and Cut the Rope
题意:切割一些绳子,让糖果能触碰地面。问切割绳子次数的最小值。
思路:只需要切钉子高度大于绳子长度的绳子。
代码:
写的复杂了点,只用拿一个一变量记录输出即可,太久没打,紧张了。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
void solve()
{
int n;
cin >> n;
vector<int> a(n), b(n);
for(int i = 0; i < n; i ++ ) cin >> a[i] >> b[i];
vector<pii> p;
set<int> st;
for(int i = 0; i < n; i ++ )
{
if(a[i] > b[i]) st.insert(i);
}
if(st.size()) cout << st.size() << '\n';
else cout << 0 << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
B. Rudolph and Tic-Tac-Toe
题意:X,+,O能以三个出现在一行,一列,对角线,就输出相应字符,否则输出'DRAW'。
思路:模拟判断即可,一定注意里面还有'.'表示这里什么都没有。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
char g[10][10];
void solve()
{
for(int i = 1; i <= 3; i ++ ) cin >> (g[i] + 1);
for(int i = 1; i <= 3; i ++ )
if(g[i][1] == g[i][2] && g[i][2] == g[i][3] && g[i][1] != '.')
{
cout << g[i][1] << '\n';
return ;
}
else if(g[1][i] == g[2][i] && g[2][i] == g[3][i] && g[1][i] != '.')
{
cout << g[1][i] << '\n';
return ;
}
if(g[1][1] == g[2][2] && g[2][2] == g[3][3] && g[1][1] != '.')
{
cout << g[1][1] << '\n';
return ;
}
else if(g[1][3] == g[2][2] && g[2][2] == g[3][1] && g[1][3] != '.')
{
cout << g[2][2] << '\n';
return ;
}
cout << "DRAW\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
C. Rudolf and the Another Competition
题意:给出每个人做的题的所花时间,求Rudolf(第一个人)能排在第几名,排名规则,以过题数为第一顺序,罚时为第二顺序。如果题数和罚时相同,Rudolf将在最前面。
思路:一个人希望过最多的题,那么一定要先做时间少的题,那么一个人的做题顺序就按照时间从小到大,算出题目数和罚时后,我们可Rudolf的序号(因为Rudolf的序号是1)进行第三顺序,进行排序即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
struct A
{
ll ct, T, idx;
};
bool cmp(A &a, A &b)
{
if(a.ct > b.ct) return true;
else if(a.ct == b.ct)
{
if(a.T < b.T) return true;
else if(a.T == b.T)
{
if(a.idx < b.idx) return true;
}
}
return false;
}
void solve()
{
int n, m, h;
cin >> n >> m >> h;
vector<vector<int>> t(n, vector<int>(m));
vector<ll> sum(n), cnt(n);
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
cin >> t[i][j];
for(int i = 0; i < n; i ++ )
{
sort(t[i].begin(), t[i].end());
int cur = 0;
for(int j = 0; j < m; j ++ )
{
if(cur + t[i][j] > h) break;
cnt[i]++;
sum[i] += t[i][j] + cur;
cur += t[i][j];
}
}
vector<A> res(n);
for(int i = 0; i < n; i ++ )
{
res[i] = {cnt[i], sum[i], i};
}
sort(res.begin(), res.end(), cmp);
for(int i = 0; i < n; i ++ )
if(res[i].idx == 0)
{
cout << i + 1 << '\n';
break;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
D. Rudolph and Christmas Tree
题意:给一个坐标轴,在上面放三角形求构成图形的面积。
思路:由于可能覆盖,减去重复的面积,用三角形相似减去重复的面积。从下往上放三角形,记录上一个三角形的的上顶点位置hei,底边的位置low,重复的面积是小三角形和给的大三角形进行相似比较可以,设当前的大三角形的底边的位置是y,小三角形的底边x,小三角形的高hei-y,,现在能求出小三角形的底边,那么小三角形面积就求出来了。注意数据类型在计算过程中可能会爆。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
void solve()
{
int n;
double d, h;
cin >> n >> d >> h;
ll low = 0, hei = 0;
double res = 0;
for(int i = 0; i < n ; i ++ )
{
int y;
cin >> y;
if(low == 0 && hei == 0)
{
res += d * h / 2;
low = y, hei = y + h;
}
else
{
if(y >= hei)
{
res += d * h / 2;
low = y, hei = y + h;
}
else
{
res += d * h / 2;
res -= (hei - y) * (hei - y) * d / h / 2;
low = y, hei = y + h;
}
}
// cout << low << ' ' << hei << endl;
// cout << res << endl;
}
printf("%.8lf\n", res);
}
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
E. Rudolf and Snowflakes
题意:首先一个点,先扩展k条边,再将只连接一条边的点扩展k条边(至少扩展到这),之后可以一直扩展下去,给我们一个n,问能否制作n个点的图形。
思路:首先发现我们(k > 1,p >= 2),求和,对于easy版本我们n<=1e6,那么枚举用map保存答案即可,范围1<k<=1e3。hard版本,n<=1e18,k的枚举范围就到1<k<=1e9,我们发现对于p>=3,k的枚举范围到1<k<=1e6,我们可以枚举,对于p=2时,我们可以的到公式,判断是否有正整数解并且大于1。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
set<ll> nums;
// 1 + k + k^1 + ... + k ^ p = (k ^ (p + 1) - 1) / (k - 1)
// 我们能预处理出来的是p >= 3,2 <= k <= 1e6(如果处理p = 2的话,那么p能到达1e9)
void init()
{
for(ll k = 2; k <= 1000000; k ++ )
{
ll val = 1 + k;
ll p = k * k;
for(int cnt = 3; cnt <= 63; cnt ++ )
{
val += p;
if(val > 1e18) break;
nums.insert(val);
if(p > (ll)(1e18) / k) break;
p *= k;
}
}
}
void solve()
{
ll n;
cin >> n;
if(n < 3)
{
cout << "NO\n";
return ;
}
if(nums.count(n))
{
cout << "YES\n";
return ;
}
//当p = 2时,我们判断k^2 + k + 1 = n是否有正整数解并且大于1
ll d = 4 * n - 3; //根的判别式
ll sq = sqrt(d);
ll sqd = -1;
for(ll i = max(0ll, sq - 5); i <= sq + 5; i ++ )
{
if(i * i == d) //d能被开方
{
sqd = i;
break;
}
}
//正整数解 (sqd - 1) / 2
if(sqd != -1 && (sqd - 1) % 2 == 0 && (sqd - 1) / 2 > 1)
{
cout << "YES\n";
}
else cout << "NO\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _;
_ = 1;
cin >> _;
init();
while(_--)
{
solve();
}
return 0;
}
F. Rudolph and Mimic
题意:给一堆物品,用数字(1~9)表示,其中有一个模仿者,它能够随意变成某一个物品,它最多只能只能两回合不变,在5个回合内我们要找到它,一个回合中我们可以选着任意个物品将之移除,移除的输出规范在题目中。
思路:分情况讨论,当前的模仿者有两种做法,一是变,二是不变。先看不变,那么就等。如果变,变又分变原来存在的物品和原来不存在的物品。变原来存在的物品就将这种物品保留下来,其他的物品移除掉,这样的话就等它变就行了。变为原来不存在的物品就直接找到。一定在5次内找到,最慢的情况第一次变了,等到第三次变,移除其他的只剩下一种类型物品,等到第5次的时候一定变。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
int a[10][210]; //存储每层数
int mp[10][20]; //记录每一层某个数出现次数
void solve()
{
int n;
cin >> n;
int cnt = 0;
vector<int> v;
a[0][0] = a[1][0] = n;
memset(mp, 0, sizeof mp);
while(1)
{
cnt++;
int idx = a[cnt - 1][0];
v.clear();
int f = 0; //f = 1时模仿者变化,f = 2时模仿者没变化
int k = 0; //模仿者变的元素
for(int i = 1; i <= idx; i ++ )
{
cin >> a[cnt][i];
mp[cnt][a[cnt][i]]++;
}
if(cnt == 1)
{
cout << "- 0\n";
continue;
}
//和上一层比较,是否有不同
for(int i = 1; i <= idx; i ++ )
{
if(mp[cnt][a[cnt][i]] != mp[cnt - 1][a[cnt][i]])
{
f = 1;
//模仿者变成上一层不存在的物品
if(mp[cnt][a[cnt][i]] && !mp[cnt - 1][a[cnt][i]])
{
cout << "! " << i << '\n';
return ;
}
if(mp[cnt][a[cnt][i]] > mp[cnt - 1][a[cnt][i]]) k = a[cnt][i];
}
}
if(f == 0) f = 2;
//模仿者没变,等
if(f == 2)
{
a[cnt][0] = idx;
cout << "- 0\n";
continue;
}
//模仿者变成上一层存在的物品,移除元素(模仿者变的元素保存下来)
if(f == 1)
{
for(int i = 1; i <= idx; i ++ )
if(a[cnt][i] != k) v.push_back(i);
cout << "- " << v.size() << ' ';
for(auto i : v) cout << i << ' ';
cout << '\n';
//移除更新状态
for(int i = 1; i <= idx - v.size(); i ++ ) a[cnt][i] = k;
for(int i = 1; i < 10; i ++ ) mp[cnt][i] = 0;
mp[cnt][k] = idx - v.size();
a[cnt][0] = idx - v.size();
}
}
}
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
G. Rudolf and CodeVid-23
题意:当前有一种二进制下的字符串每一位表示一种症状(1为有,0为没有),并给出m个其他的字符串,使用后需要等d天后吃其他药,吃完后有相应的症状治疗和副作用,症状治疗相应的位置为1的话治疗该位置的症状,0无效果。副作用相应的位置为1会拥有该症状。问能否痊愈的吃药最短天数,如果不能输出-1。
思路:将它看成从给的状态下到全0的状态的最短路。所有状态为2^10(字符串长度10),用Dijkstra算法。每一个点都可以无限的使用其他的药,如果能到达状态0,即能到达。对于一个状态使用药后转移到另一个状态,当前状态为i,治愈j,副作用k,那么最后的状态i & (~j) | k。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, mod = 1e9 + 7, INF = 0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pii;
void solve()
{
int n, m;
cin >> n >> m;
bitset<10> tmp;
cin >> tmp;
int s = tmp.to_ulong();
vector<pair<pii, int>> edges(m);
for(int i = 0; i < m; i ++ )
{
cin >> edges[i].second;
cin >> tmp;
int cur = ((1 << n) - 1) ^ tmp.to_ulong();
edges[i].first.first = cur;
cin >> tmp;
edges[i].first.second = tmp.to_ulong();
}
vector<int> dist(1 << n, INF), vis(1 << n);
dist[s] = 0;
set<pii> q;
q.insert({0, s});
while(q.size())
{
auto [d, v] = *q.begin();
q.erase(q.begin());
if(vis[v]) continue;
vis[v] = 1;
for(int i = 0; i < m; i ++ )
{
int to = v & edges[i].first.first;
to |= edges[i].first.second;
if(dist[to] > d + edges[i].second)
{
dist[to] = d + edges[i].second;
q.insert({dist[to], to});
}
}
}
if(dist[0] == INF) dist[0] = -1;
cout << dist[0] << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int _;
_ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}