2024.11.12

今日总结:
1:http://www.nfls.com.cn:10611/p/P862
这道题主要是考察树上差分和lca,学习了树上差分,这道题也可用用dfs+bfs+lca来解决

点击查看代码
#include<bits/stdc++.h>

using namespace std;

#define int long long

const int N = 2e5 + 10;

int n,Min;
int d[N],f[N][30],c1[N],c2[N],num[N],ans[N];

struct Node
{
    vector<int> nxt,nxt_v1,nxt_v2;
}Node[N];

void bfs(int v)
{
    queue<int> q;
    d[v] = 1;
    q.push(v);
    int t = (int)(log(n) / log(2)) + 1;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int i = 0;i < Node[u].nxt.size();i ++)
        {
            int y = Node[u].nxt[i];
            if(d[y] != 0) continue;
            d[y] = d[u] + 1;
            f[y][0] = u;
            int v1 = Node[u].nxt_v1[i],v2 = Node[u].nxt_v2[i];
            c1[y] = v1,c2[y] = v2;
            for(int j = 1;j <= t;j ++)
                f[y][j] = f[f[y][j - 1]][j - 1];
            q.push(y);
        }
    }
}

int LCA(int x,int y)
{
    int t = (int)(log(n) / log(2)) + 1;
    if(d[x] > d[y]) swap(x,y);
    for(int i = t;i >= 0;i--)
        if(d[f[y][i]] >= d[x]) y = f[y][i];
    if(x == y) return x;
    for(int i = t;i >= 0;i --)
        if(f[y][i] != f[x][i]) y = f[y][i],x = f[x][i];
    return f[x][0];
}

int dfs(int now,int fa)
{
    ans[now] += num[now];
    for(int i = 0;i < Node[now].nxt.size();i ++)
    {
        int y = Node[now].nxt[i];
        if(fa != y) ans[now] += dfs(y,now);
    }
    return ans[now];
} 

signed main()
{
    freopen("coffee.in","r",stdin);
    freopen("coffee.out","w",stdout);
    scanf("%lld",&n);
    for(int i = 1;i <= n - 1;i ++)
    {
        int u,v,v1,v2;
        scanf("%lld%lld%lld%lld",&u,&v,&v1,&v2);
        Node[u].nxt.push_back(v),Node[v].nxt.push_back(u);
        Node[u].nxt_v1.push_back(v1),Node[v].nxt_v1.push_back(v1);
        Node[v].nxt_v2.push_back(v2),Node[u].nxt_v2.push_back(v2);
    }
    bfs(1);
    for(int i = 2;i <= n;i ++)
    {
        int u = i - 1,v = i,z = LCA(u,v);
        num[u] += 1,num[v] += 1,num[z] -= 2;
    }
    dfs(1,-1);
    for(int i = 2;i <= n;i ++)
    {
        int v1 = c1[i],v2 = c2[i],t = ans[i];
        Min += min(v1 * t,v2);
    }
    printf("%lld\n",Min);
    return 0;
}

2:http://www.nfls.com.cn:10611/p/P592
这道题主要是一道图论的题,可以用优先队列优化

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1010;

int n,m,startx,starty,endx,endy;
int st[N][N],north[N][N],south[N][N],east[N][N],west[N][N];
int dx[5] = {-1,1,0,0},dy[5] = {0,0,1,-1};
string s[N];

struct Node
{
    int x,y,dis;
    bool operator<(const Node &a)const{return dis > a.dis;}
};

priority_queue<Node> pq;

int main()
{
    freopen("portals.in","r",stdin);
    freopen("portals.out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(st,0x3f,sizeof(st));
    for(int i = 1;i <= n;i ++)
    {
        cin >> s[i];
        s[i] = '#' + s[i] + '#';
        for(int j = 1;j <= m;j ++)
        {
            if(s[i][j] == 'S') startx = i,starty = j;
            if(s[i][j] == 'C') endx = i,endy = j;
        }
    }
    // if(startx == endx && starty == endy) 
    // {
    //     printf("0\n");
    //     return 0;
    // }
    for(int i = 0;i <= m + 1;i ++)
        s[0] += '#',s[n + 1] += '#';
    for(int i = 1;i <= m;i ++)
        for(int j = 1;j <= n;j ++)
            if(s[j][i] != '#')  north[j][i] = north[j - 1][i] + 1;
    for(int i = 1;i <= m;i ++)
        for(int j = n;j >= 1;j --)  
            if(s[j][i] != '#') south[j][i] = south[j + 1][i] + 1;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= m;j ++)
            if(s[i][j] != '#') east[i][j] = east[i][j - 1] + 1;
    for(int i = 1;i <= n;i ++)
        for(int j = m;j >= 1;j --) 
            if(s[i][j] != '#') west[i][j] = west[i][j + 1] + 1;
    pq.push(Node{startx,starty,0});
    st[startx][starty] = 0;
    while(pq.size())
    {
        Node t = pq.top();
        pq.pop();
        for(int i = 0;i < 4;i ++)
        {
            int zx = t.x + dx[i],zy = t.y + dy[i];
            if(zx >= 1 && zx <= n && zy >= 1 && zy <= m && s[zx][zy] != '#' && st[t.x][t.y] + 1 < st[zx][zy])
            {
                st[zx][zy] = st[t.x][t.y] + 1;
                pq.push(Node{zx,zy,st[zx][zy]});
            }
        }
        int val = min({north[t.x][t.y],south[t.x][t.y],east[t.x][t.y],west[t.x][t.y]}) - 1;
        int door_n = t.x - north[t.x][t.y] + 1,door_s = t.x + south[t.x][t.y] - 1,door_e = t.y - east[t.x][t.y] + 1,door_w = t.y + west[t.x][t.y] - 1;
        if(st[t.x][t.y] + val + 1 < st[door_n][t.y])
        {
            st[door_n][t.y] = st[t.x][t.y] + val + 1;
            pq.push(Node{door_n,t.y,st[door_n][t.y]});
        }
        if(st[t.x][t.y] + val + 1 < st[door_s][t.y])
        {
            st[door_s][t.y] = st[t.x][t.y] + val + 1;
            pq.push(Node{door_s,t.y,st[door_s][t.y]});
        }
        if(st[t.x][t.y] + val + 1 < st[t.x][door_e])
        {
            st[t.x][door_e] = st[t.x][t.y] + val + 1;
            pq.push(Node{t.x,door_e,st[t.x][door_e]});
        }
        if(st[t.x][t.y] + val + 1 < st[t.x][door_w])
        {
            st[t.x][door_w] = st[t.x][t.y] + val + 1;
            pq.push(Node{t.x,door_w,st[t.x][door_w]});
        }
    }
    printf("%d\n",st[endx][endy]);
    return 0;
}

3:https://www.luogu.com.cn/problem/P3537
这道题是一道背包的题目,但题目非常新颖,一定要考虑边界问题

点击查看代码
//dp[k]表示,在满足a <= m的物品中c属性之和为k的方案中最小的b属性的最大值
#include<bits/stdc++.h>

using namespace std;

const int N = 1010;
const int M = 1e6 + 10;

int n,q;
int dp[M];
bool ans[M];

struct Node1
{
    int a,b,c;
    bool operator<(const Node1 &x)const {return a < x.a;}
}a[N];

struct Node2
{
    int m,k,s,id;
    bool operator<(const Node2 &x)const{return m < x.m;}
}b[M];

int main()
{
    // freopen("Cloakroom.in","r",stdin);
    // freopen("Cloakroom.out","w",stdout);
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
        scanf("%d%d%d",&a[i].c,&a[i].a,&a[i].b);
    scanf("%d",&q);
    for(int i = 1;i <= q;i ++)
        scanf("%d%d%d",&b[i].m,&b[i].k,&b[i].s),b[i].id = i;
    sort(a + 1,a + n + 1);
    sort(b + 1,b + q + 1);
    dp[0] = 1 << 30;
    for(int i = 1,j = 1;i <= q;i ++)
    {
        for(;j <= n && a[j].a <= b[i].m;j ++)
            for(int k = 1e5;k >= a[j].c;k --)
                dp[k] = max(dp[k],min(dp[k - a[j].c],a[j].b));
        if(dp[b[i].k] > b[i].m + b[i].s) ans[b[i].id] = 1;
    }
    for(int i = 1;i <= q;i ++)
        puts(ans[i] ? "TAK" : "NIE");
    return 0;
}

4:http://www.nfls.com.cn:20035/contest/2090/problem/4#submit_code
这道题是一道状压DP,Dp的定义以后可以设为持续时间状态,状压基本思路

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1010;

int n,l;
int val[N],num[N][N],dp[1 << 21];

int main()
{
    scanf("%d%d",&n,&l);
    for(int i = 0;i < n;i ++)
    {
        scanf("%d%d",&val[i],&num[i][0]);
        for(int j = 1;j <= num[i][0];j ++)
            scanf("%d",&num[i][j]);
    }
    int ans = 0x3f3f3f3f;
    memset(dp,-1,sizeof(dp));
    dp[0] = 0;
    for(int t = 0;t < (1 << n);t ++)
    {
        if(dp[t] == -1) continue;
        for(int i = 0;i < n;i ++)
        {
            if((t >> i) & 1) continue;
            int *p = upper_bound(num[i] + 1,num[i] + num[i][0] + 1,dp[t]) - 1;
            if(p != num[i]) dp[t|(1 << i)] = max(dp[t|(1 << i)],num[i][p - num[i]] + val[i]);
            else dp[t|(1 << i)] = dp[t];
        }
        if(dp[t] >= l) ans = min(ans,__builtin_popcount(t));
    }
    if(ans == 0x3f3f3f3f) puts("-1");
    else printf("%d\n",ans);
    return 0;
}
posted @ 2024-11-12 22:15  Kevinhwbb  阅读(3)  评论(0编辑  收藏  举报