点对最大值

题意

这里有一棵树,每个点和每条边都存在一个价值。对于树上点对的价值,包括点对的起点和终点以及路径上边权值之和,不包括路径上其他点值。
求这颗树上最大的点对价值为多少。点对至少需要两个点。

思路

典型树形dp,当时看题太快了,没注意到必须要两个点。
定义表示为的一条子链的的最大价值(只包含一个点权)。
显然转移方程为

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 2001110;
const int M = 1e9+7;
int n,ans;

int a[maxn];

int head[maxn],cost[maxn],to[maxn],Next[maxn],cnt = 2;

void add(int u,int v,int w)
{
    to[cnt] = v;cost[cnt] = w;Next[cnt] = head[u];head[u] = cnt;cnt++;
}

int dp[maxn];

//至少两个点

void dfs(int u,int pre)
{  
    dp[u] = a[u];
    for(int i = head[u]; i ; i = Next[i])
    {
        int v = to[i];
        if(v == pre) continue;
        dfs(v,u);
        ans = max(ans,dp[u]+dp[v]+cost[i]);
        dp[u] = max(dp[u],dp[v]+cost[i]);
    }
}

signed main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
#endif
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i = 1; i <= n; i++)
        {
            head[i] = 0;
        }
        cnt=2;ans = -1000;
        for(int i = 2,x,y; i <= n; i++)
        {
            cin>>x>>y;
            add(i,x,y);add(x,i,y);
        }
        for(int i = 1; i <= n; i++)
        {
            cin>>a[i];
        }
        dfs(1,1);
        cout<<ans<<endl;
    }
    return 0;
}

扔硬币

题意

有n枚硬币,每枚硬币扔出来是正面和反面的概率各占50%。小明同时扔下了n枚硬币后,已知至少有m枚硬币是反面。请问恰好有k枚硬币是正面的概率是多少。

思路

比赛看了半天没看懂题意,就是抛硬币,会有许多情况,就是问在全部情况中(除去m枚以下硬币朝下的情况)恰好k枚硬币朝上的概率是多少?
我们可以用k枚朝上的样本数除以总的样本数

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 201110;
const int M = 1e9+7;
int n,m,k,ok;

int inv[maxn];

void init()
{   
    inv[1] = 1;
    for(int i = 2; i < maxn; i++) 
    {
        inv[i] = (M-M/i)*inv[M%i]%M;
    }
}

int c(int x,int y) 
{   
    if(y > x) return 0;
    int res = 1;
    y = min(y,x-y);
    for(int i = 1; i <= y; i++) 
    {
        res = (res*(x-i+1)%M*inv[i])%M;
    }
    return res;
}

int ksm(int a,int b)
{
    int res = 1;
    while (b)
    {
        if(b&1) res = (res*a)%M;
        a = (a*a)%M;
        b /= 2;
    }
    return res%M;
}

signed main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
#endif
    int T;
    cin>>T;
    init();
    while(T--)
    {
        cin>>n>>m>>k;
        int b = 1,a = 1;
        if(m+k > n) cout<<0<<endl;
        else
        {   
            int x = 1;
            for(int i = 1; i < m; i++) 
            {
                x = x*(n-i+1)%M*inv[i]%M;
                b = (b+x)%M;
            }
            b = (ksm(2,n)-b+M)%M;
            a = c(n,k);
            cout<<(a*ksm(b,M-2)%M)<<endl;
        }
    }
    return 0;
}

养花

题意

题目太长了,不说了,当你知道这题是用网络流来解决的时候你已经做出来了。
建一个虚拟起点,然后k点就是终点,跑最大流就行了

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 110;
const int maxm = 201110;
const int M = 1e9+7;
int n,m,s,t;

int a[maxn],b[maxn][maxn];

int head[maxn],cost[maxm],to[maxm],Next[maxm],cnt = 2;

void ad(int u,int v,int w)
{
    to[cnt] = v;cost[cnt] = w;Next[cnt] = head[u];head[u] = cnt;cnt++;
}

void add(int u,int v,int w)
{
    ad(u,v,w);ad(v,u,0);
}

int level[maxn];

int bfs()
{
    mem(level,0);
    level[s] = 1;
    queue<int> q;q.push(s);
    while(!q.empty())
    {
        int u = q.front();q.pop();
        for(int i = head[u]; i ; i = Next[i])
        {
            int v = to[i];
            if(cost[i] > 0 && level[v] == 0)
            {
                level[v] = level[u] + 1;
                q.push(v);
            }
        }
    }
    return level[t];
}

int dfs(int u,int flow)
{
    if(u == t) return flow;
    int res = flow;
    for(int i = head[u]; i ; i = Next[i])
    {
        if(res == 0) break;
        int v = to[i];
        if(cost[i] && level[v] == level[u]+1)
        {
            int k = dfs(v,min(res,cost[i]));
            res -= k;cost[i] -= k;cost[i^1] += k;
        }
    }
    return flow-res;
}

int dinic()
{
    int ans = 0;
    while(bfs())
    {
        ans += dfs(s,inf);
    }
    return ans;
}

signed main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
#endif
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m>>t;s = 101;
        mem(a,0);mem(b,0);
        mem(head,0);cnt = 2;
        for(int i = 1,x; i <= n; i++) 
        {
            cin>>x;
            a[x]++;
        }
        for(int i = 1; i <= 100; i++) 
        {
            if(a[i]) add(s,i,a[i]);
        }
        int op,x;
        int a1,a2,b1,b2;
        while(m--)
        {
            cin>>op>>x;
            if(op == 1)
            {
                cin>>a1>>b1;
                b[a1][b1] += x;
            }
            else if(op == 2)
            {
                cin>>a1>>a2>>b1;
                for(int i = a1; i <= a2; i++) 
                {
                    b[i][b1] += x;
                }
            }
            else if(op == 3)
            {
                cin>>a1>>b1>>b2;
                for(int i = b1; i <= b2; i++) 
                {
                    b[a1][i] += x;
                }
            }
            else
            {
                cin>>a1>>a2>>b1>>b2;
                for(int i = a1; i <= a2; i++) 
                {
                    for(int j = b1; j <= b2; j++) 
                    {
                        b[i][j] += x;
                    }
                }
            }
        }
        for(int i = 1; i <= 100; i++) 
        {
            for(int j = 1; j <= 100; j++) 
            {
                if(b[i][j]) add(i,j,b[i][j]);
            }
        }
        cout<<dinic()<<endl;
    }
    return 0;
}

字典序

题意

小明遇到了一个问题希望你能帮他解决
现在有n个数字排成一列构成数组A,数组A中存在n个数a[i], 其中1<=i<=n。
数组sj为删除数组A中的第j个数后,剩余n-1个数构成的数组,其中1<=j<=n。
小明希望你把s1~sn的数组按照字典序大小排列起来,
若两个数组相等,则认为删除元素编号小的数组字典序更小

思路

我也是看了题解之后才想出来的,感觉很奇妙。 说明删去或者的序列一模一样,不过删的字典序会更小 说明删去的序列会比删去任何一个大于的序列的字典序大,因为删去的序列第位是,而删去大于的序列第位是,显然字典序会更小。
同理, 情况则相反

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 201110;
const int M = 1e9+7;
int n,m,k,ok;

int a[maxn];

int ans[maxn];

struct node
{
    int id,x;
    bool operator < (const node tmp) const
    {
        if(x == tmp.x) return id < tmp.id;
        return x < tmp.x;
    }
}b[maxn];

int dfs(int i,int k)
{   
    if(i == n)
    {
        ans[i] = k;
        return ans[i];
    }
    if(a[i] == a[i+1])
    {
        ans[i] = dfs(i+1,k);
    }
    if(a[i] < a[i+1])
    {
        ans[i] = k+(n-i);
        dfs(i+1,k);
    }
    if(a[i] > a[i+1])
    {
        ans[i] = k;
        dfs(i+1,k+1);
    }
    return ans[i];
}

signed main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
#endif
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i = 1; i <= n; i++) 
        {
            cin>>a[i];
        }
        dfs(1,1);
        for(int i = 1; i <= n; i++) 
        {
            //cout<<ans[i]<<' ';
            b[i].id = i;
            b[i].x = ans[i];
        }
        sort(b+1,b+1+n);
        for(int i = 1; i <= n; i++) 
        {
            cout<<b[i].id<<' ';
        }
        cout<<endl;
    }
    return 0;
}