天天看点

2019CCPC女生赛C - Function HDU - 6546 D - TreeF - String

C - Function HDU - 6546 

由于a大于0,所有二次函数均是开口向上,而且x必须正整数。所以很自然想到先全部分配1.

然后逐个分配,由于二次函数f[i]-f[i-1]左边一定比右边更优,即i越小结果越小。

所以我们可以直接把F[I]-F[I-1]丢到优先队列里。每次让某一个二次函数的x+1,根据前面的分析,一定是队列首的二次函数加1 更优,因为队列里的所有数,将来只可能更大,不会变小。

然后把F[I+1]-F[I]丢回去即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e5+7;
struct node
{
	ll f,x,id;
	bool operator <(const node &r)const
	{
		return f>r.f;
	}
}p;
priority_queue<node>q;//逆序规则,变成小根堆 
int a[M],b[M],c[M];
ll s(int k,int x)
{
	return 1LL*a[k]*x*x+1LL*b[k]*x+c[k];
}
int main()
{
	int n,m;
	cin>>n>>m;
	ll ans=0;
	for(int i=1;i<=n;i++)
	cin>>a[i]>>b[i]>>c[i],ans+=s(i,1),q.push(node{s(i,2)-s(i,1),2,i});
	m-=n;
	while(m)
	{
		node tp=q.top();q.pop();
		ans+=tp.f;
		q.push(node{s(tp.id,tp.x+1)-s(tp.id,tp.x),tp.x+1,tp.id});
		m--;
	}
	cout<<ans<<endl;
	return 0;
}
           

D - Tree

 HDU - 6547

如果不在树上,这就是一道势能线段树的裸题。

在树上的话,树剖一下就行了。

两个知识点的混合板子题

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls o*2
#define rs o*2+1
const int maxn=2e5+7;
ll w[maxn],wt[maxn];
struct node
{
    int v,nxt;
}e[maxn];
int tot,head[maxn];
void add(int x,int y)
{
    e[++tot].nxt=head[x];
    e[tot].v=y;
    head[x]=tot;
}
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
int n,m,r,q;
void init()
{
    tot=0,cnt=0;
}
ll tr[maxn<<2],tg[maxn<<2];
void bd(int o,int l,int r)
{
    if(l==r)
    {
        tr[o]=wt[l];
        if(tg[o]==1||tg[o]==0)tg[o]=1;
        return;
    }
    int m=(l+r)/2;
    bd(ls,l,m);
    bd(rs,m+1,r);
    tr[o]=tr[ls]+tr[rs];
}
void up(int o,int l,int r,int x,int y)
{
    if(l==r)
    {
        tr[o]=sqrt(1.0*tr[o]);
        if(tr[o]==1||tr[o]==0)
        tg[o]=1;
        return ;
    }
    int m=(l+r)/2;
    if(x<=m)up(ls,l,m,x,y);
    if(y>m)up(rs,m+1,r,x,y);
    tr[o]=tr[ls]+tr[rs];
    if(tg[ls]&&tg[rs])tg[o]=1;
}
ll qu(int o,int l,int r,int x,int  y)
{
    if(x<=l&&r<=y)
    {
        return tr[o];
    }
    int m=(l+r)/2;
    ll ans=0;
    if(x<=m)ans+=qu(ls,l,m,x,y);
    if(y>m)ans+=qu(rs,m+1,r,x,y);
    return ans;
}
//
void dfs1(int u,int f,int deep)
{
    dep[u]=deep;
    fa[u]=f;
    siz[u]=1;
    int maxson=-1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==f)continue;
        dfs1(v,u,deep+1);
        siz[u]+=siz[v];
        if(siz[v]>maxson)
        {
            son[u]=v;
            maxson=siz[v];
        }
    }
}
void dfs2(int u,int topf)
{
    id[u]=++cnt;
    wt[cnt]=w[u];
    top[u]=topf;
    if(!son[u])return ;
    dfs2(son[u],topf);
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}
void updrange(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[x]<dep[y])
            swap(x,y);
        up(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    up(1,1,n,id[x],id[y]);
}
ll qrange(int x,int y)
{
    ll ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        ans+=qu(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    ans+=qu(1,1,n,id[x],id[y]);
    return ans;
}
int main()
{
    int u,v;
    init();
    cin>>n>>q;
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i]);

    for(int i=1;i<=n-1;i++)
        scanf("%d%d",&u,&v),add(u,v),add(v,u);
    r=1;
    dfs1(r,-1,1);
    dfs2(r,r);
    bd(1,1,n);
    for(int i=1;i<=q;i++)
    {
        int opt,u,v,z;
        scanf("%d%d%d",&opt,&u,&v);
        if(opt==0)
        {
            updrange(u,v);
        }
        else{
            printf("%lld\n",qrange(u,v));
        }
    }
}
           

F - String

 HDU - 6549 

f[i][j][k]表示: 处理到第i位,使当前位修改为 'a'+j ,且已经出现了k段的最小修改次数。

由于无后效性,我们直接线性DP从前往后推。

比较简单,难点是会自然想到26^2*10*n的做法。

我们让f[i][26][k]表示: 处理到第i位,使当前位修改为任意字符 ,且已经出现了k段的最小修改次数。

这样就能利用前面已经处理过的信息了 省去一维枚举字符。

转移比较简单,看看就差不多了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)]  //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 2e5+7;
/*int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}*/
int f[M][27][11];
char s[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
 	int n,l,z;
	cin>>n>>l>>z;
	cin>>s;
	memset(f,127,sizeof(f));
	for(int i=0;i<=25;i++)
	f[0][i][1]=(s[0]=='a'+i?0:1);
	f[0][26][1]=0;
	for(int i=1;i<n;i++)
	{
		for(int j=0;j<25;j++)
		{
			for(int k=1;k<=z;k++)
			{
				if(s[i]=='a'+j)f[i][j][k]=f[i-1][j][k];
				if(i-l>0)
				{
					f[i][j][k]=min(f[i][j][k],f[i-l][26][k-1]+1);
					f[i][j][k]=min(f[i][j][k],f[i-l][j][k]+1);
				}
				else
				{
					f[i][j][k]=min(f[i][j][k],f[0][26][k-1]+1);
					f[i][j][k]=min(f[i][j][k],f[0][j][k]+1);
				}
			//	cout<<i<<" "<<j<<" "<<k<<" "<<f[i][j][k]<<endl;
				f[i][26][k]=min(f[i][26][k],f[i][j][k]);
			}
		}
	} 	
	cout<<f[n-1][26][z]<<endl;
	return 0;
}