感谢(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;
}