天梯赛选拔赛
L1-033 出生年
传送门
当时看y的范围没注意以为是最高到3000结果是y的范围是3000所以是最高从3000开始
#include <bits/stdc++.h>
using namespace std;
int main()
{
int y, n;cin >> y >> n;
int res= -1;
for(int i = y ;i <= 9999; i ++)
{
set<int>a;
string s = to_string(i);
for(int j = 0 ;j < 4; j ++)
{
if(j < s.size())a.insert(s[j] - '0');
else a.insert(0);
}
if(a.size() == n)
{
res = i;
break;
}
}
printf("%d %.04d\n", res - y, res);
}
非常弹的球
传送门
纯粹的物理题,当时没看出来这里是等比数列求和QAQ
#include <bits/stdc++.h>
using namespace std;
const double g = 9.8,eps = 1e-6;
int main()
{
double w,p;cin >> w >> p;
w /= 100.00000000000;
double prec = (double)p / 100;
double v0 = sqrt(2000/w);
double v1 = v0 / sqrt(2);
cout <<fixed << setprecision(3) << v1*(v1 / g) * 2/prec << endl;
return 0;
}
病毒溯源
传送门
题目大意:给出一个(或者多个)无环联通有向图,要求找出其中从根节点出发最长的那一条路线,如果长度一样就输出字典序最小的那个路线
题目思路:就是直接dfs然后对于dfs的返回值是vector也就是路线,然后我们存储一下每一个根节点的最长且字典序最小的路线之后排序输出答案,在搜索的时候有一步优化,那就是对于路线的存储我们倒过来存(其实如果用list的话就不用这样了,不过我没有选择list因为不太熟QWQ),因为这样就可以直接在存入路线的时候直接push_back进去避免头插增加时间复杂度,只有在遇到长度一样的时候需要把两个路线倒过来来比较一下,不过这种情况不会太多(大概QWQ)
题目思路
(纪念一下咱头一次搜索在现场写出来力hhh,佬说这道题应该用拓扑排序,但我直接暴搜加剪枝也过了)
以下是代码(写法1 递归 + 路径保存)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
vector<int> dfs(vector<vector<int>>&g, int x, int fa)
{
vector<int>res;
res.push_back(x);
for(int i = 0 ;i < g[x].size(); i ++)
{
int v = g[x][i];
if(v == fa) continue;
auto t = dfs(g, v, x);
t.push_back(x);
if(t.size() > res.size())
{
res = t;
continue;
}
if(t.size() == res.size())
{
auto temp = res, temp1 = t;
reverse(temp1.begin() ,temp1.end());
reverse(temp.begin(), temp.end());
if(temp > temp1) res = t;
}
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;cin >> n;
vector<vector<int>>g(n);
vector<bool>fa(n, 0);
for(int i = 0 ;i < n ;i ++)
{
int k;cin >> k;
for(int j = 0 ;j < k; j ++)
{
int x;cin >> x;
fa[x] = true;
g[i].push_back(x);
}
}
vector<int>rt;
for(int i = 0 ;i < n; i ++) if(!fa[i]) rt.push_back(i);
vector<vector<int>>res(rt.size());
for(int i = 0 ;i < rt.size() ;i ++)
{
res[i] = dfs(g,rt[i], -1);
reverse(res[i].begin(), res[i].end());
}
sort(res.begin(), res.end());
cout << res[0].size() << endl;
for(int i = 0 ;i < res[0].size(); i ++) cout << res[0][i] << " \n"[i == res[0].size() - 1];
return 0;
}
写法2(栈 + 矩阵排序)
#include<bits/stdc++.h>
using namespace std;
// map_ 存储树的邻接表,map_[i][0] 表示节点 i 的子节点数量,后续 map_[i][1..] 为子节点编号
int map_[10001][10002] = {0};
// re_map 记录每个节点的父节点,根节点的父节点为 -1
int re_map[10001] = {-1};
// re 记录当前找到的最长路径的节点数(即链的长度)
int re = 1;
// end_ 记录最长路径的终点节点
int end_ = 0;
// visited 标记节点是否已被访问,用于全局遍历控制
bool visited[10001] = {0};
// 从节点 st 开始进行深度优先遍历,寻找从 st 出发能到达的最深深度,并更新全局最长路径
void how(int st) {
// 如果当前节点已访问,直接返回(注意:这个判断会导致后续节点无法再次遍历,可能造成问题)
if (visited[st]) return;
// 使用栈模拟DFS,栈中元素为 (当前节点, 当前深度)
stack<pair<int, int> > stk;
stk.push({st, 1});
while (!stk.empty()) {
pair<int, int> cur = stk.top();
stk.pop();
visited[cur.first] = 1; // 标记当前节点为已访问
if (cur.second > re) { // 如果当前深度大于全局最大深度,更新
re = cur.second;
end_ = cur.first;
}
// 遍历当前节点的所有子节点,将其压入栈中,深度加1
for (int i = 1; i <= map_[cur.first][0]; i++) {
stk.push({map_[cur.first][i], cur.second + 1});
}
}
}
// 比较函数,用于降序排序
bool cmp(int a, int b) {
return a > b;
}
int main() {
int n;
cin >> n;
// 初始化父节点数组为 -1
for (int i = 0; i < n; i++) {
re_map[i] = -1;
}
// 读入每个节点的子节点信息
for (int i = 0; i < n; i++) {
cin >> map_[i][0]; // 读入子节点个数
for (int j = 1; j <= map_[i][0]; j++) {
cin >> map_[i][j]; // 读入子节点编号
re_map[map_[i][j]] = i; // 记录子节点的父节点为 i
}
}
// 对每个节点的子节点列表进行降序排序(从大到小),
// 目的是在DFS时优先访问编号大的子节点,从而在相同路径长度下得到字典序较大的路径
// 但题目通常要求字典序最小,此处排序方向可能相反
for (int i = 0; i < n; i++) {
if (map_[i][0] < 2) continue; // 少于2个子节点无需排序
sort(map_[i] + 1, map_[i] + (map_[i][0] + 1), cmp);
}
// 对每个节点调用 how 函数,但由于 visited 全局标记,实际只会从第一个未被访问的节点开始遍历,
// 后续节点因为已被访问而直接返回,因此只进行了一次DFS,无法保证找到整棵树的最长路径
for (int i = 0; i < n; i++) {
how(i);
}
// 根据找到的终点 end_,利用父指针 re_map 回溯得到整条路径
int chain[10001] = {end_}; // 存储路径上的节点,从终点开始
int p = 1;
for (p = 1;; p++) {
if (re_map[chain[p - 1]] == -1) break; // 到达根节点
chain[p] = re_map[chain[p - 1]]; // 继续向上找父节点
}
// 输出路径长度(节点数)
cout << re << endl;
// 逆序输出路径(从根到终点)
for (int i = p - 1; i >= 0; i--) {
cout << chain[i];
if (i != 0) cout << " ";
}
return 0;
}
L2-018 多项式A除以B
传送门
思路:学习ingQWQ
#include <bits/stdc++.h>
using namespace std;
int const N = 100000 + 10;
double const eps = 1e-8;
double const eps2 = 0.05;
int n,e,cnt1,cnt2;
double a[N],b[N],c,ans[N],res[N]; //a[e] = c,表示cx^e,系数可能为浮点数,但是指数一定是整数
void solve(){
for(int i=N-1;i>=0;i--) if(fabs(a[i]) > eps){ //枚举a的每一项
for(int j=N-1;j>=0;j--) if(fabs(b[j]) > eps){
if(i < j) return;
c = a[i] / b[j]; //系数相除
e = i - j; //指数相减
ans[e] = c; //答案的一项
break;
}
for(int j=N-1;j>=0;j--) res[j] = 0;
for(int j=N-1;j>=0;j--) if(fabs(b[j]) > eps){ //多项式B的每一项都乘以cx^e
res[j+e] = c * b[j];
}
for(int j=N-1;j>=0;j--) //两式相减得余数
a[j] = a[j] - res[j];
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) //多项式A
cin>>e>>c, a[e] = c;
scanf("%d",&n);
for(int i=1;i<=n;i++) //多项式B
cin>>e>>c, b[e] = c;
solve();
for(int i=N-1;i>=0;i--){
if(fabs(ans[i]) >= eps2) cnt1++;
if(fabs(a[i]) >= eps2) cnt2++;
}
if(cnt1 == 0) printf("0 0 0.0\n");
else{
printf("%d",cnt1);
for(int i=N-1;i>=0;i--) if(fabs(ans[i]) >= eps2) printf(" %d %.1lf",i,ans[i]);
printf("\n");
}
if(cnt2 == 0) printf("0 0 0.0\n");
else{
printf("%d",cnt2);
for(int i=N-1;i>=0;i--) if(fabs(a[i]) >= eps2) printf(" %d %.1lf",i,a[i]);
}
return 0;
}

浙公网安备 33010602011771号