2024.11.21
今日总结 上午比赛,下午改题,晚上做题
比赛总结:以后一定要检查数组范围,提交文件,一定要删光Debug代码!!!
1:厂州塔
这道题是一道典型的贪心,只需要对每次取完的数据,排一下序就可以了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node
{
ll x,y;
};
ll n,k ;
vector<Node> a,b;
bool cmp(Node &l,Node &r)
{
return l.x < r.x;
}
bool Solve(vector<Node> &a,ll k)
{
sort(a.begin(),a.end(),cmp);
for(auto i : a)
{
k -= i.x;
if(k < 1) return false;
k += i.y;
}
return true;
}
int main()
{
// freopen("tower.in","r",stdin);
// freopen("tower.out","w",stdout);
ll T;
scanf("%lld",&T);
while(T --)
{
a.clear(),b.clear();
scanf("%lld%lld",&n,&k);
ll now = k;
for(ll i = 1;i <= n;i ++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
now += y - x;
if(x <= y) a.push_back({x,y});
else b.push_back({y,x});
}
if(Solve(a,k) && Solve(b,now)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
2:界外科学
这道题是一道这般搜索的好题,只需要预处理出来Pow把他建成树,在树上建01串,主要原因是因为题目要求我们求异或,然后在树上折半搜索就可以,但一定要注意数组和最大值开的范围
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long INF = 400000000000000000;
const int M = 5e7 + 10;
const int upp = 55,N = 55;
ll n,m,ans,rt,flag = 1;
ll a[N],b[N],Pow[upp];
vector<ll> l,r;
struct Node
{
void init()
{
u[0] = -1,u[1] = -1;
fa = 1;
Max = -INF;
}
ll u[2];
ll fa, Max;
}edge[M];
void Name()
{
Pow[0] = 1;
for(ll i = 1; i <= upp; i++)
Pow[i] = Pow[i - 1] * 2; // 2 4 6
}
void Insert(ll num, ll v)
{
ll son = rt;
for(ll i = upp;i >= 0;i --)
{
edge[son].Max = max(edge[son].Max,v);
edge[son].fa ++;
ll y = (num & Pow[i]) / Pow[i];
if(edge[son].u[y] == -1)
{
edge[flag].init();
edge[son].u[y] = flag;
flag ++;
}
son = edge[son].u[y];
}
// cout << '*' << flag << endl;
edge[son].Max = max(edge[son].Max,v);
}
ll dfs(ll num,ll m,ll depth,ll root)
{
if(root == -1) return -INF;
if(depth == -1) return edge[root].Max;
ll x = (num & Pow[depth]) / Pow[depth],y = (m & Pow[depth]) / Pow[depth];
ll res = -INF;
if(y == 0)
{
if(x == 0) res = dfs(num,m,depth - 1,edge[root].u[0]);
else res = dfs(num,m,depth - 1,edge[root].u[1]);
// cout << '*' << res << endl;
}
else
{
if(x == 0) // 左
{
ll id = edge[root].u[0];
if(id != -1) res = edge[id].Max;
res = max(res, dfs(num,m,depth - 1,edge[root].u[1]));
}
else // 右
{
ll id = edge[root].u[1];
if (id != -1) res = edge[id].Max;
res = max(res, dfs(num,m,depth - 1,edge[root].u[0]));
}
}
return res;
}
int main()
{
// freopen("science.in","r",stdin);
// freopen("science.out","w",stdout);
scanf("%lld%lld",&n,&m);
Name();
bool st = false;
for(ll i = 0;i < n;i ++)
scanf("%lld",&a[i]);
for(ll i = 0;i < n;i ++)
scanf("%lld",&b[i]);
if(n == 1)
{
if (a[0] <= m) ans = max(ans,b[0]);
printf("%lld\n",ans);
return 0;
}
for(ll i = 0;i < n;i ++) // 1,4,6
{
if(i < n / 2) l.push_back(i);
else r.push_back(i);
}
edge[rt].init();
for(ll t = 0;t < Pow[l.size()];t ++)
{
ll x = 0,y = 0;
for(ll L = 0; L < l.size();L ++)
if(t & Pow[L]) x ^= a[l[L]],y += b[l[L]]; // 0,1,100,0 1->0
// cout << x << " " << y << endl;
Insert(x, y);
}
for(ll t = 0;t < Pow[r.size()];t ++)
{
ll x = 0, y = 0;
for(ll R = 0; R < r.size();R ++)
if(t & Pow[R]) x ^= a[r[R]],y += b[r[R]]; // 0->1
ans = max(ans,y + dfs(x,m,upp,rt));
}
printf("%lld\n",ans);
return 0;
}
3:City
这道题是一道有向图的强连同分量,还需要用到并查集合并,对下标进行操作
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 5e5 + 10;
ll n, m, x, q, fa[N], sn[N], tt, sum, sz2[N], sn2[N], cnt, lp[N], locate[N], begins[N], ans;
bool offer[N];
struct node
{
ll sz, bh;
} s[N];
bool cmp(const node &a1, const node &a2)
{
if (a1.sz == a2.sz)
{
return a1.bh < a2.bh;
}
return a1.sz < a2.sz;
}
ll get(ll nw)
{
if (nw == fa[nw])
return nw;
fa[nw] = get(fa[nw]);
return fa[nw];
}
void push(ll x, ll y)
{
fa[get(x)] = get(y);
}
void pd1()
{
if (m < max(sum, n - x + 1) || x > tt + n - sum)
{
printf("-1\n");
exit(0);
}
}
void pd2()
{
cnt = 1;
if (x < n - sum + 1)
{
for (int i = 1; i <= n; i++)
{
if (offer[i])
{
sn2[i] = 1;
sz2[1]++;
}
}
for (int i = 1, j = 1; i <= n; i++)
{
if (!offer[i])
{
if (n - sum - j >= x - 1)
{
sn2[i] = 1;
sz2[1]++;
}
else
{
sn2[i] = ++cnt;
sz2[cnt]++;
}
j++;
}
}
}
else
{
// cout<<tt<<endl;
for (int i = tt; i >= 1; i--)
{
if (i + n - sum >= x)
{
lp[s[i].bh] = 1;
}
else
{
lp[s[i].bh] = ++cnt;
}
}
for (int i = 1; i <= n; i++)
{
if (!offer[i])
{
sn2[i] = ++cnt;
sz2[cnt]++;
}
else
{
sn2[i] = lp[sn[i]];
sz2[lp[sn[i]]]++;
}
}
}
ll tot = 0, tot2 = 0;
for (int i = 1; i <= cnt; i++)
{
tot += sz2[i] * (sz2[i] - 1 + tot2);
tot2 += sz2[i];
}
if (m > tot)
{
printf("-1");
exit(0);
}
}
signed main()
{
scanf("%lld %lld %lld %lld", &n, &m, &x, &q);
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
for (int i = 1; i <= q; i++)
{
ll x, y;
scanf("%lld %lld", &x, &y);
push(x, y);
offer[x] = offer[y] = true;
}
for (int i = 1; i <= n; i++)
{
if (!offer[i])
continue;
sum++;
if (!sn[get(i)])
sn[i] = sn[get(i)] = ++tt;
else
sn[i] = sn[get(i)];
s[sn[i]].sz++;
s[sn[i]].bh = sn[i];
}
pd1();
sort(s + 1, s + tt + 1, cmp);
pd2();
for (ll i = 1; i <= n; i++)
{
// cout<<i<<" referred to "<<sn2[i]<<endl;
if (locate[sn2[i]])
{
printf("%lld %lld\n", locate[sn2[i]], i);
fa[locate[sn2[i]]] = i;
locate[sn2[i]] = i;
ans++;
}
else
{
begins[sn2[i]] = locate[sn2[i]] = i;
}
}
for (ll i = 1; i <= x; i++)
{
if (locate[i] != begins[i])
{
printf("%lld %lld\n", locate[i], begins[i]);
fa[locate[i]] = begins[i];
ans++;
}
}
for (ll i = 1; i <= n; i++)
{
for (ll j = 1; j <= n; j++)
{
if (ans >= m)
{
break;
}
if (j != fa[i] && sn2[j] >= sn2[i] && j != i)
{
printf("%lld %lld\n", i, j);
ans++;
}
}
}
return 0;
}
4:旅行家的预算
这道题是一道贪心+dfs的题目,用到dfs的原因是因为这道题目需要考虑油箱容量的问题,油箱是有上限的
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
double d1, c, d2, p, ans = 1e6, cn[10][2];
int n;
void get(int x, double s, double m)
{
if (s < 0 || s > c)
return;
if (x == n + 1)
{
ans = min(ans, m);
return;
}
for (int i = x; i <= n + 1 && (cn[i][0] - cn[x][0]) / d2 <= c; i++)
if ((cn[i][0] - cn[x][0]) / d2 <= s)
get(x + 1, s - (cn[x + 1][0] - cn[x][0]) / d2, m);
else
get(x + 1, (cn[i][0] - cn[x][0]) / d2 - (cn[x + 1][0] - cn[x][0]) / d2, m + ((cn[i][0] - cn[x][0]) / d2 - s) * cn[x][1]);
get(x + 1, c - (cn[x + 1][0] - cn[x][0]) / d2, m + (c - s) * cn[x][1]);
}
int main()
{
cin >> d1 >> c >> d2 >> p >> n;
for (int i = 1; i <= n; i++)
cin >> cn[i][0] >> cn[i][1];
cn[0][1] = p, cn[n + 1][0] = d1; // 初始化
get(0, 0, 0); // 从起点开始搜索
if (ans == 1e6)
cout << "No Solution";
else
printf("%.2lf", ans);
return 0;
}
5:圣诞树
这道题第一次的思路是图论的思路,但是实现好像是需要O(n^3)这显然很容易TLE,转换思路考虑Dp,观察题目,他的连边顺序分别是从根节点向两边延申分成了两个区间,而这个形状又不符合树,所以只能是区间Dp,但定义需要额外才开有一维,而这一维则需要设为在哪一个区间中,这很难想,因为会有区间相交的情况,Dp转移很好想一边从内向外一边从外向内,但是只有了最小值,却没有路径,这时应该记录路径的前驱就可以
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int n;
int pre[N][N][3];
double dp[N][N][3];
struct Node
{
double x,y;
int id;
}a[N],tmp[N];
double dis(int i,int j)
{
return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}
void Print(int l,int r,int flag)
{
if(l == r) return printf("%d ",a[l].id),void();
if(flag) printf("%d ",a[r].id),Print(l,r - 1,pre[l][r][flag]);
else printf("%d ",a[l].id),Print(l + 1,r,pre[l][r][flag]);
}
int main()
{
// freopen("christmas.in","r",stdin);
// freopen("christmas.out","w",stdout);
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
a[i].id = i;
tmp[i] = a[i];
}
int Max = 1;
for(int i = 2;i <= n;i ++)
if(a[Max].y < a[i].y) Max = i;
for(int i = 1;i <= Max;i ++)
a[i + n - Max] = tmp[i];
for(int i = Max + 1;i <= n;i ++)
a[i - Max] = tmp[i];
for(int len = 2;len < n;len ++)
{
for(int l = 1,r = len;r < n;l ++,r ++)
{
dp[l][r][0] = dp[l][r][1] = 1e18;
if(dp[l][r][0] > dp[l + 1][r][0] + dis(l,l + 1)) dp[l][r][0] = dp[l + 1][r][0] + dis(l,l + 1),pre[l][r][0] = 0;
if(dp[l][r][0] > dp[l + 1][r][1] + dis(l,r)) dp[l][r][0] = dp[l + 1][r][1] + dis(l,r),pre[l][r][0] = 1;
if(dp[l][r][1] > dp[l][r - 1][0] + dis(r,l)) dp[l][r][1] = dp[l][r - 1][0] + dis(l,r),pre[l][r][1] = 0;
if(dp[l][r][1] > dp[l][r - 1][1] + dis(r,r - 1)) dp[l][r][1] = dp[l][r - 1][1] + dis(r,r - 1),pre[l][r][1] = 1;
}
}
printf("%d ",a[n].id);
if(dp[1][n - 1][0] + dis(1,n) > dp[1][n - 1][1] + dis(n - 1,n)) Print(1,n - 1,1);
else Print(1,n - 1,0);
return 0;
}