Beavermuncher-0xFF

利用巧妙的树形递归
对于一个非叶子节点u来说,是到达1次某个节点能吃掉的最大数量,应该挑出最大的,(v是u的子节点)。之后如果u节点还有剩余的海狸(说明还能继续吃子树上的),那么对子节点扫一遍,看看是否有剩余的。
对于叶子节点,或是只有1个的海狸节点,不可能继续往下走,直接令它的sz等于1然后返回
坑1:n=1的时候ans=0
坑2:数据范围爆int
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define maxn (100000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("input.txt","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int head[maxn],to[maxn<<1],pre[maxn<<1],tot;
int n,s;
int num[maxn];
ll sz[maxn];
int buf[maxn];
void adde(int u,int v){to[++tot]=v,pre[tot]=head[u],head[u]=tot;}
bool cmp(int a,int b){
    return sz[a]>sz[b];
}
void dfs(int u,int fa)
{
    if(u!=s)num[u]--,sz[u]=1;
    if(num[u]==0)return;
    bool f=1;
    for(int i=head[u];i;i=pre[i])
    {
        int v=to[i];if(v==fa)continue;
        dfs(v,u);f=0;
    }
    if(f){sz[u]=1;return;}
    int pb=0;
    for(int i=head[u];i;i=pre[i])
    {
        int v=to[i];if(v==fa)continue;
        buf[pb++]=v;//see(u),see(v),NL;
    }
    //see(sz[u]),NL;
    sort(buf,buf+pb,cmp);
    for(int i=0;i<pb;i++)
    {
        int v=buf[i];
        if(num[u])sz[u]+=sz[v]+1,num[u]--;
        else break;
        //see(sz[u]),NL;
    }
    for(int i=0;i<pb;i++)
    {
        int v=buf[i];
        if(num[u])
        {
            if(num[v])
                sz[u]+=1LL*min(num[u],num[v])*2,
                num[u]-=min(num[u],num[v]);
        }
        else break;
    }
}
int main()
{
    RD1(n);for(int i=1;i<=n;i++)RD1(num[i]);
    for(int i=1;i<n;i++){int u,v;RD2(u,v);adde(u,v),adde(v,u);}RD1(s);
    if(n==1)printf("0");
    else 
    {
        dfs(s,0);cout<<sz[s];
    }
    return 0;
}

OpenStreetMap

经典的单调队列问题,先按第一维单调队列,保存在c中,再按第二维单调队列,保存在c2中。
注意,c如果重复使用,千万要主要更新的先后顺序。因为这个debug好久,后来索性开了c2
表示以i,j为长a宽b的矩形中的最小值
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define maxn (3000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("input.txt","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll mp[maxn][maxn];
ll c[maxn][maxn];
ll c2[maxn][maxn];
ll n,m,a,b,g,x,y,z;
int main()
{
    RDL2(n,m),RDL2(a,b),RDL1(g),RDL3(x,y,z);
    for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++)
        mp[i][j]=g,g=(g*x+y)%z;
    for(ll i=1;i<=n;i++)
    {
        deque<ll>Q;
        for(ll j=1;j<=m;j++)
        {
            while(!Q.empty()&&mp[i][Q.back()]>=mp[i][j])Q.pop_back();
            //see(i),see(j),see(mp[i][Q.front()]),NL;
            Q.push_back(j);
            c[i][j]=mp[i][Q.front()];
            while(!Q.empty()&&Q.front()<=j-b+1)Q.pop_front();
        }
    }
//for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)printf("%d ",c[i][j]);printf("\n");}
    ll ans=0;
    for(ll j=1;j<=m;j++)
    {
        deque<ll>Q;
        for(ll i=1;i<=n;i++)
        {
            //see(i),see(j),NL;for(deque<ll>::iterator it=Q.begin();it!=Q.end();it++)see(*it);NL;
            while(!Q.empty()&&c[Q.back()][j]>=c[i][j])    Q.pop_back();
            Q.push_back(i);
            c2[i][j]=c[Q.front()][j];
            if(i>=a&&j>=b)ans+=c2[i][j];
            while(!Q.empty()&&Q.front()<=i-a+1)Q.pop_front();
        }
    }
//for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)printf("%d ",c2[i][j]);printf("\n");}
    cout<<ans;
    return 0;
}

网络流,建立源点(0)和汇点(n+26+1),中间第一层是字符串,n个节点(27~26+n),第二层字母,26个节点(1~26)
源点到各字符串的cap是ai,字符串到字母的cap是每个字母的个数,字母到汇点(目标字符串)的cap是目标字符串每种字母的个数
字符串到字母的有费用,其余为0
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (1000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
char buf[maxn];
int c1[30];
int c2[200][30];
int lim[maxn];
int s,t;
int tot,head[maxn],pre[maxn<<4],to[maxn<<4],
cap[maxn<<4],flow[maxn<<4],cost[maxn<<4];
void adde(int u,int v,int cp,int spt)
{
    to[tot]=v,pre[tot]=head[u],head[u]=tot,
    cap[tot]=cp,cost[tot]=spt,flow[tot]=0,
    tot++;
}
int dis[maxn];
bool in[maxn];
int last[maxn];
bool bfs()
{
    INF(dis),CLR(in),NEG(last);
    queue<int>Q;Q.push(s);
    dis[s]=0;
    in[s]=1;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();in[u]=0;
        for(int i=head[u];~i;i=pre[i])
        {
            int v=to[i];
            int c=cost[i];
            int cp=cap[i];
            int f=flow[i];
            if(dis[u]+c<dis[v]&&f<cp)
            {
                dis[v]=dis[u]+c,
                last[v]=i;
                if(!in[v])
                {
                    in[v]=1;Q.push(v); 
                }
            }
        }
    }
    return last[t]!=-1;
}
void mfmc(int &cst,int &flw)
{
    flw=cst=0;
    while(bfs())
    {
        int Min=inf;
        for(int i=last[t];~i;i=last[to[i^1]])
            Min=min(Min,cap[i]-flow[i]);
        for(int i=last[t];~i;i=last[to[i^1]])
            flow[i]+=Min,
            flow[i^1]-=Min,
            cst+=Min*cost[i];
        flw+=Min;
    }
}
int main()
{
    scanf("%s",buf);
    int n;RD1(n);
    s=0,t=26+n+1;
    NEG(head);
    int sum=strlen(buf);
    for(int i=0;i<sum;i++)c1[buf[i]-'a'+1]++;
    for(int i=1;i<=26;i++)if(c1[i])adde(i,t,c1[i],0),adde(t,i,0,0);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",buf);RD1(lim[i]);
        for(int j=0;buf[j];j++)c2[i][buf[j]-'a'+1]++;
        adde(s,i+26,lim[i],0),adde(i+26,s,0,0);
    }
    for(int i=1;i<=26;i++)
    {
        if(!c1[i])continue;
        for(int j=1;j<=n;j++)
        {
            if(!c2[j][i])continue;
            adde(j+26,i,c2[j][i],j),adde(i,j+26,0,-j);
        }
    }
    int cst,flw;mfmc(cst,flw);
    if(flw!=sum)printf("-1");
    else printf("%d",cst);
    return 0;
}