20南京站M题(树上dp)19南京站J题(KM算法)+思维

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20南京站M题(树上dp)19南京站J题(KM算法)+思维相关的知识,希望对你有一定的参考价值。

M. Monster Hunter

树上背包。对于父节点和子节点,都是可选可不选,删除的点是任意的,但要满足价值最小。
状态设计:
dp[u][num][0]表示以u为根节点(不包含自身),选择num个子节点,能获取的最小价值。
dp[u][num][1]表示以u为根节点(包含自身),选择num个子节点,能获取的最小价值。

状态转移:f[u][i+j][0]=min(f[u][i+j][0],f[u][i][0]+min(f[v][j][0],f[v][j][1]));
u结点不选被删掉,因此子节点并不对父节点产生额外的的贡献。
相反,f[u][i+j][1]=min(f[u][i+j][1],f[u][i][1]+min(f[v][j][0],f[v][j][1]+hp[v]));
u结点被选择,子节点的权值会被父节点累加上。

实现:双重循环枚举出u和v不同的取值,从后向前,滚动更新。

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
const int P=131;
const int N=3e3+5;
int n,a[N],hp[N],f[2005][2005][2],sz[N];
vector<int>e[N];
void dfs(int u,int fa)

    f[u][1][1]=hp[u],f[u][0][0]=0;
    sz[u]=1;
    for(int v:e[u])
    
        if(v==fa) continue;
        dfs(v,u);
        for(int i=sz[u];i>=0;i--)
        
            for(int j=sz[v];j>=0;j--)
            
                f[u][i+j][0]=min(f[u][i+j][0],f[u][i][0]+min(f[v][j][0],f[v][j][1]));
                f[u][i+j][1]=min(f[u][i+j][1],f[u][i][1]+min(f[v][j][0],f[v][j][1]+hp[v]));
            
        
        sz[u]+=sz[v];
    

void solve()

    cin>>n;
    for(int i=0;i<=n;i++) e[i].clear(),sz[i]=0;
    for(int i=2;i<=n;i++)
    
        int x;cin>>x;
        e[i].push_back(x);e[x].push_back(i);
    
    for(int i=1;i<=n;i++) cin>>hp[i];
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            f[i][j][0]=f[i][j][1]=inf;
    dfs(1,0);
    for(int i=0;i<=n;i++)
        cout<<min(f[1][n-i][0],f[1][n-i][1])<<" ";
    cout<<endl;

signed main()

    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;

模板 - KM算法(O(n^3))(二分图最大权完美匹配)

(记录下大佬的链接~)

J. Spy

具体证明过程:https://zhuanlan.zhihu.com/p/562593632
思考过程:
读懂题意后,对于Bob来说需要对两类成员进行随机组合,使得累加值在和Alice进行比赛时,能得到最大的分数,要求出最大的期望分数*n的值。
1.对于数组B和C组合出的数组D,有n!种方案,那么期望的分数即为p[i]/n! (if d[i]>a[i])
2.对于数组d的搭配也有n!种方案,则平均每个d[i]有n!/n种方案数。
3.因此公式为: (n!/n)*(p[i]的和/n!)

KM板子是抄其他大佬的

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
//const int P=131;
const int N=400+5;
int w[N][N],lx[N],ly[N];
bool visx[N],visy[N];
int match[N],delta,n,c[N],p[N];
int A[N],P[N],B[N],C[N];
void bfs(int x)         // O(n^3)的KM板子

    int a,y=0,y1=0;
    for(int i=1;i<=n;i++) p[i]=0,c[i]=inf;
    match[y]=x;
    do
        a=match[y],delta=inf,visy[y]=1;
        for(int b=1;b<=n;b++)
        
            if(!visy[b])
            
                if(c[b]>lx[a]+ly[b]-w[a][b])
                    c[b]=lx[a]+ly[b]-w[a][b],p[b]=y;
                if(c[b]<delta) delta=c[b],y1=b;
            
        
        for(int b=0;b<=n;b++)
            if(visy[b]) lx[match[b]]-=delta,ly[b]+=delta;
            else c[b]-=delta;
        y=y1;
    while(match[y]);
    while(y)
        match[y]=match[p[y]],y=p[y];

int KM()

    for(int i=1;i<=n;i++) match[i]=lx[i]=ly[i]=0;
    for(int i=1;i<=n;i++)
    
        for(int i=0;i<=n;i++) visy[i]=0;
        bfs(i);
    
    int res=0;
    for(int i=1;i<=n;i++) res+=w[match[i]][i];
    return res;


void solve()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>A[i];
    for(int i=1;i<=n;i++) cin>>P[i];
    for(int i=1;i<=n;i++) cin>>B[i];
    for(int i=1;i<=n;i++) cin>>C[i];
    for(int i=1;i<=n;i++)
    
        for(int j=1;j<=n;j++)
        
            int sum=0;
            for(int k=1;k<=n;k++)
                if(A[k]<B[i]+C[j]) sum+=P[k];
            w[i][j]=sum;
        
    
    cout<<KM()<<endl;

signed main()

    ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;



C.Rolling Girl

数论题。
我想到了很多东西,都是对的。没做出来一是复杂度没算对,不敢尝试;而是代码的实现没找到适合的写法,导致没自信。
思路:
1.很容易想到对于不同步长走过的数字要选取一个权值最小的点。
2.对于和n互为质数的步长,要走n轮。
3.二则相乘为该步长的跳跃次数。写法可直接对1~n进行遍历,测试下来最大不到4e8,可以过题。
太妙了。

#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const int N=1e7+5;
const int inf=1e18;
const int p=1004535809;
unsigned seed, mod;
unsigned read() 
    seed ^= seed << 13;
    seed ^= seed >> 5;
    seed ^= seed << 7;
    return seed % mod + 1;

int n,a[N],ans[N];
int fun(int x)

    int mi=inf;
    for(int i=x;i<=n;i+=x)
    
        if(mi>a[i]) mi=a[i];
    
    return mi%p*(n/x)%p;

void solve()

    cin>>n;
    cin>>seed>>mod;
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++)
    
        if(n%i==0)
        
            ans[i]=fun(i);
            for(int j=i;j<=n;j+=i) ans[j]=ans[i];
        
    
    int sum=0;
    for(int i=1;i<=n;i++) sum=(sum+ans[i])%p;
    cout<<sum<<endl;

signed main()

    ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;



D. Masha and a Beautiful Tree

递推做法:

#include <bits/stdc++.h>
//#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
#define down 0.996
using namespace std;
const double eps=1e-8;
const double inf=1e18;
const int mod=998244353;
//const int P=131;
const int N=3e6+5;
int qpow(int x,int y)

    int res=1;
    while(y)
    
        if(y&1) res=res*x;
        x=x*x;
        y>>=1;
    
    return res;

int n,a[N];
void solve()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans=0,flag=0;

    for(int i=0;i<=n;i++)
    
        int g=qpow(2,i);
        int p=1,q=1+g;
        if(q>n) break;
        while(q<=n)
        
            if(a[p]+g==a[q])
            
                //cout<<1<<" "<<p<<" "<<q<<endl;
                p+=2*g;q+=2*g;
            
            else if(a[p]==a[q2018ACM-ICPC亚洲区域赛南京站I题Magic Potion(网络流)

2018 ACM-ICPC南京区域赛题解

计蒜客 30994 - AC Challenge - [状压DP][2018ICPC南京网络预赛E题]

2019 ICPC南京站 B题 Chessboard组合数,乘法逆元

ICPC亚洲区域赛(南京) M.Monster Hunter(树形dp)

2018南京网络赛L