POI2015选做

感谢(darkbzoj)的倾情赞助

以下题目不是按照难度顺序进行排序

bzoj4386

推荐完成:luogu4159

假设边权全部为(1)怎么做?

一般是直接快速幂,方便统计答案我们让所有点向一个虚拟汇点连边,这个虚拟汇点再连一个自环,接下来直接倍增即可

但是这里的边权是(1-3),于是按照上题的思路考虑拆点,将点(u)拆成((u,0),(u,1),(u,2)),每一条边可以看做是((u,w))连向((v,0))

代码如下

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define fir first
#define sec second
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define maxd 1000000007
#define eps 1e-6
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
struct matrix{
	ll x[130][130];
}bin[70];
int n,m;ll k;
matrix operator *(matrix a,matrix b)
{
	matrix c;
	rep(i,0,n*3)
		rep(j,0,n*3) c.x[i][j]=0; 
	rep(i,0,n*3)
	{
		rep(j,0,n*3)
		{
			rep(k,0,n*3) c.x[i][j]+=a.x[i][k]*b.x[k][j];
		}
	}
	return c;
}

int calc(matrix a)
{
	ll tmp=0;
	rep(i,1,n)
	{
		if (tmp>=k-(a.x[i][0]-1)) return 1;
		tmp+=a.x[i][0]-1;
	}
	return 0;
}

int read()
{
	int x=0,f=1;char ch=getchar();
	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
	return x*f;
}

int main()
{
	n=read();m=read();scanf("%lld",&k);
	bin[0].x[0][0]=1;
	rep(i,1,n)
	{
		bin[0].x[i][0]=1;
		bin[0].x[i][i+n]=1;
		bin[0].x[i+n][i+n+n]=1;
	}
	rep(i,1,m)
	{
		int u=read(),v=read(),w=read();
		bin[0].x[u+(w-1)*n][v]++;
	}
	int pos,flag=0;
	rep(i,1,64)
	{
		bin[i]=bin[i-1]*bin[i-1];
		if (calc(bin[i])) {pos=i-1;flag=1;break;}
	}
	if (!flag) {puts("-1");return 0;}
	ll ans=0;
	matrix tmp,now;
	rep(i,1,n) now.x[i][i]=1; 
	per(i,pos,0)
	{
		tmp=now*bin[i];
		if (!calc(tmp)) {now=tmp;ans+=(1ll<<i);}
	}
	printf("%lld",ans);
	return 0;
} 

bzoj4380

对于第一问,我们进行区间(dp),记(dp_{l,r,i})表示在区间([l,r])中的最小值为(k)时的最大收益,那么肯定是要将读入的(c_i)全部离散化的,并且在这里只考虑在([l,r])中的人的需求

接下来考虑转移,直接枚举最小值(k)的位置,有(dp_{l,r,i}=max(dp_{l,pos-1,c_1}+dp_{pos+1,r,c_2}+g_{pos,i}*cost_i)),其中(c_1geq i,c_2geq i)(g_{pos,i})表示包含(pos)(cgeq i)的区间数

方便转移,我们再记(f_{l,r,i}=max(dp_{l,r,j})(jgeq i)),于是方程的前两项可以直接用(f)代替

对于第二问输出方案,我们记录每次转移(dp)的值的时候的决策点(pos),直接(dfs)即可

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define fir first
#define sec second
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define maxd 1000000007
#define eps 1e-6
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
int n,m,x[10010],siz,dp[60][60][4100],f[60][60][4100],g[60][4100],
	pos[60][60][4100],ans[4100];
struct node{
	int l,r,c;
}p[4100];

int read()
{
	int x=0,f=1;char ch=getchar();
	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
	return x*f;
}

void dfs(int l,int r,int k)
{
	if (l>r) return;
	if (!f[l][r][k])
	{
		rep(i,l,r) ans[i]=x[k];
		return;
	}
	rep(i,k,siz)
	{
		if (dp[l][r][i]==f[l][r][k])
		{
			int now=pos[l][r][i];
			ans[now]=x[i];
			dfs(l,now-1,i);
			dfs(now+1,r,i);
			break;
		}
	}
}

int main()
{
	n=read();m=read();
	rep(i,1,m)
	{
		p[i].l=read();p[i].r=read();p[i].c=read();
		x[i]=p[i].c;
	}
	sort(x+1,x+1+m);
	siz=unique(x+1,x+1+m)-x-1;
	rep(i,1,m) p[i].c=lower_bound(x+1,x+1+siz,p[i].c)-x;
	per(l,n,1)
	{
		rep(r,l,n)
		{
			rep(i,l,r)
				rep(j,1,siz) g[i][j]=0;
			rep(i,1,m)
			{
				if ((p[i].l>=l) && (p[i].r<=r))
					rep(j,p[i].l,p[i].r) g[j][p[i].c]++;
			}
			rep(i,l,r)
				per(j,siz-1,0) g[i][j]+=g[i][j+1];
			rep(i,l,r)
			{
				per(j,siz,1)
				{
					int tmp=f[l][i-1][j]+f[i+1][r][j]+g[i][j]*x[j];
					if (dp[l][r][j]<tmp) {pos[l][r][j]=i;dp[l][r][j]=tmp;}
					f[l][r][j]=max(f[l][r][j+1],dp[l][r][j]);
				}
			}
		}
	}
	dfs(1,n,1);
	printf("%d
",f[1][n][1]);
	rep(i,1,n) printf("%d ",ans[i]);
	return 0;
}

bzoj3747

枚举左端点,同时选取合适的右端点,更新答案

可以将问题转化成为最大子段和问题,具体的,对于第一次出现的位置,对答案的贡献为(w_i),第二次出现时贡献为(-w_i)(为了与之前的抵消),这之后都是(0),每一次暴力修改

辣鸡bzoj卡我空间

// luogu-judger-enable-o2
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define fir first
#define sec second
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
struct node{
    ll sum,maxl,maxr,maxsum;
}seg[4004000];
int n,m,f[1001000],w[1001000],pos[1001000],len[1001000];
vector<int> kind[1001000];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void pushup(int id)
{
    seg[id].sum=seg[id<<1].sum+seg[id<<1|1].sum;
    seg[id].maxl=max(seg[id<<1].maxl,seg[id<<1|1].maxl+seg[id<<1].sum);
    seg[id].maxr=max(seg[id<<1|1].maxr,seg[id<<1].maxr+seg[id<<1|1].sum);
    seg[id].maxsum=max(max(seg[id<<1].maxsum,seg[id<<1|1].maxsum),seg[id<<1].maxr+seg[id<<1|1].maxl);
}

void modify(int id,int l,int r,int pos,int val)
{
    //cout << id << " " << l << " " << r << " " << pos << " " << val << endl;
    //system("pause");
    if (l==r)
    {
        seg[id].sum=val;seg[id].maxl=val;
        seg[id].maxr=val;seg[id].maxsum=val;
        return;
    }
    int mid=(l+r)>>1;
    if (pos<=mid) modify(id<<1,l,mid,pos,val);
    else modify(id<<1|1,mid+1,r,pos,val);
    pushup(id);
}

void out(int id,int l,int r)
{
    if (l==r) 
    {
        cout << seg[id].sum << " ";
        return;
    }
    int mid=(l+r)>>1;
    out(id<<1,l,mid);out(id<<1|1,mid+1,r);
}

int main()
{
    n=read();m=read();
    rep(i,1,n)
    {
        f[i]=read();len[f[i]]++;
        kind[f[i]].push_back(i);
    }
    rep(i,1,m) w[i]=read();
    rep(i,1,m)
    {
        if (len[i]>=1) modify(1,1,n,kind[i][0],w[i]);
        if (len[i]>=2) modify(1,1,n,kind[i][1],-w[i]);
    }
    ll ans=0;
    rep(i,1,n)
    {
        ans=max(ans,seg[1].maxsum);
        modify(1,1,n,i,0);
        pos[f[i]]++;
        if (pos[f[i]]<len[f[i]]) modify(1,1,n,kind[f[i]][pos[f[i]]],w[f[i]]);
        if (pos[f[i]]+1<len[f[i]]) modify(1,1,n,kind[f[i]][pos[f[i]]+1],-w[f[i]]);
    }
    printf("%lld",ans);
    return 0;
}

bzoj4378

对于(geq s)的数,它们可以在每一次操作中出现,记一共有(x)个这样的数,那么还剩下(c-x)个空位

对于(<s)的数,每一个数(a_i)可以看成是(a_i)个大小为(1)的物体放入(s)个大小为(c-x)的抽屉中,询问是否放的满

(sum=sum_{a_i<s}a_i),那么必须有(sumgeq (c-x)*s)

两个树状数组维护,一个维护([1,x])之间有多少个数,另一个维护([1,x])之间的数的和

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define int long long
#define lowbit(x) (x)&(-x)
#define fir first
#define sec second
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
struct qnode{
    int op,x,y;
}q[1001000];
int n,siz,x[1001000],a[1001000],m;
char op[100];
struct BIT{
    ll t[2000100];
    
    void add(int pos,int val)
    {
        int i;
        for (i=pos;i<=siz;i+=lowbit(i)) t[i]+=val;
    }
    
    ll query(int pos)
    {
        int i;ll ans=0;
        for (i=pos;i;i-=lowbit(i)) ans+=t[i];
        return ans;
    }
}c1,c2;

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

signed main()
{
    n=read();m=read();
    rep(i,1,m)
    {
        scanf("%s",op);
        q[i].x=read();q[i].y=read();
        if (op[0]=='U') q[i].op=0;else q[i].op=1;
        x[i]=q[i].y;
    }
    sort(x+1,x+1+m);
    siz=unique(x+1,x+1+m)-x-1;
    rep(i,1,m)
    {
        q[i].y=lower_bound(x+1,x+1+siz,q[i].y)-x;
        if (!q[i].op)
        {
            if (a[q[i].x]>0) 
                {c1.add(a[q[i].x],-1);c2.add(a[q[i].x],-x[a[q[i].x]]);}
            c1.add(q[i].y,1);c2.add(q[i].y,x[q[i].y]);
            a[q[i].x]=q[i].y;
        }
        else
        {
            int cnt=c1.query(siz)-c1.query(q[i].y-1);
            ll sum=c2.query(q[i].y-1);
            if (sum>=((ll)q[i].x-cnt)*x[q[i].y]) puts("TAK");else puts("NIE");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/encodetalker/p/10823194.html