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;
}
posted @ 2024-11-21 22:09  Kevinhwbb  阅读(5)  评论(0编辑  收藏  举报