拆开高斯函数后,动态开点线段树优化DP
啊啊啊啊为什么只有50分
淦,没有把线段树的mx值赋成-INF。。。
代码:
#include
#include
#include
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 222222
#define LOG 30
#define LL long long
const LL INF=0x3f3f3f3f3f3f3f3fll;
int c[N],x,y,z,A,m[N];
LL f[N];
struct node{
int l,r;LL x;
}a[N*LOG];
int rt,tot;
void insert(int &i,int l,int r,int x,LL k)
{
if(!i)i=++tot,a[i].x=-INF;
a[i].x=max(a[i].x,k);
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)insert(a[i].l,l,mid,x,k);
else insert(a[i].r,mid+1,r,x,k);
}
LL query(int i,int l,int r,int ql,int qr)
{
if(!i||l>qr||r>1;
return max(query(a[i].l,l,mid,ql,qr),query(a[i].r,mid+1,r,ql,qr));
}
struct anode{
int c,m;
bool operator == (const anode &t)const{
return c==t.c;
}
}tmp[N];
int main()
{
freopen("tourist.in","r",stdin);
freopen("tourist.out","w",stdout);
int n,i;
x=gi();y=gi();z=gi();A=gi();n=gi();
tmp[1].c=x;tmp[n+2].c=y;
for(i=2;i<=n+1;i++){tmp[i].c=gi();tmp[i].m=gi();}
n=n+2;
if(tmp[n]==tmp[n-1])n--;
if(tmp[1]==tmp[2]){for(i=1;i
题解:生成函数
每个珠子都要选择一种颜色,当一种颜色的珠子有k个时,这种颜色就可以贡献floor(k/2)个袋子
设有A种颜色拥有奇数颗珠子,这些珠子的个数为x
那么总袋子数就为(n-x)/2+(x-A)/2>=m
化一下可得n-2*m>=A (A<=D)
一种颜色有奇数k颗珠子选择它的方案数为C(n,k)=n!/(k!*(n-k)!)
我们选择指数型生成函数来解决这个问题
(这个问题本质上就是把每个珠子分配一种颜色,再将相同颜色的去重,其实就是可重集的全排列)
那么一种颜色的指数生成函数就是
代码:(注意一下二项式反演的部分)
#include
#include
#include
using namespace std;
#define N 300005
const int mod=998244353;
const int inv2=499122177;
int fac[N],finv[N];
int wl,wn[N],rev[N];
int ksm(int x,int y)
{
int ret=1;x=(x%mod+mod)%mod;
while(y){
if(y&1)ret=1ll*ret*x%mod;
y>>=1;x=1ll*x*x%mod;
}
return ret;
}
void shai()
{
int i,n=100000;
fac[0]=fac[1]=finv[0]=finv[1]=1;
for(i=2;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
finv[n]=ksm(fac[n],mod-2);
for(i=n;i>=1;i--)finv[i-1]=1ll*finv[i]*i%mod;
wl=1<<18;wn[0]=1;wn[1]=ksm(3,(mod-1)/wl);
for(i=2;i<=wl;i++)wn[i]=1ll*wn[i-1]*wn[1]%mod;
}
int C(int x,int y)
{
return 1ll*fac[x]*finv[y]%mod*finv[x-y]%mod;
}
void NTT(int a[],int len,int flg)
{
for(int i=1;i>1;i>=1)for(int j=0;j>1]>>1)|(i&1?len>>1:0);
NTT(A,len,1);NTT(B,len,1);
for(i=0;i
题解:
分别考虑每一段1[l,r]的贡献(用set来维护连续段)
它可以使所有满足l<=a<=b<=r的[a,b]都加上它的存在时间(在它结束(分被裂或者合并)的时候统计)
把询问看作2维上的一个点
转为动态二维数点后CDQ分治+静态二维数点即可
代码:
#include
#include
#include
#include
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 300005
#define LL long long
set S;
set::iterator it1,it2;
struct node{
int x,y,v,t,id;
node(){}
node(int a,int b,int c,int d,int e){x=a;y=b;v=c;t=d;id=e;}
bool operator < (const node &T)const{
return x>1,ql=l,qr=mid+1;
for(int i=l;i<=r;i++){
if(q[i].t<=mid){
tmp[ql++]=q[i];
if(q[i].v)update(q[i].y,q[i].v);
}
else{
tmp[qr++]=q[i];
if(!q[i].v)ans[q[i].id]+=query(q[i].y);
}
}
for(int i=l;i<=r;i++)
if(q[i].t<=mid&&q[i].v)update(q[i].y,-q[i].v);
for(int i=l;i<=r;i++)q[i]=tmp[i];
solve(l,mid);solve(mid+1,r);
}
int main()
{
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
int i,x,l,r;
n=gi();Q=gi();scanf("%s",ss+1);
S.insert(0);S.insert(n+1);
for(i=1;i<=n;i++){
vis[i]=ss[i]-'0';
if(!vis[i])S.insert(i);
}
for(i=1;i<=Q;i++){
scanf("%s",op);
if(op[0]=='t'){
x=gi();it1=it2=S.lower_bound(x);
if(vis[x]){
it1--;
cnt++,q[cnt]=node(*it1+1,*it2-1,i-las[*it1],cnt,0);
if(*it1!=x-1)las[*it1]=i;
if(*it2!=x+1)las[x]=i;
S.insert(x);
}
else{
it1--;it2++;
if(*it1!=x-1)cnt++,q[cnt]=node(*it1+1,x-1,i-las[*it1],cnt,0);
if(*it2!=x+1)cnt++,q[cnt]=node(x+1,*it2-1,i-las[x],cnt,0);
S.erase(x);las[*it1]=i;
}
vis[x]^=1;
}
else{
l=gi();r=gi()-1;
cnt++,q[cnt]=node(l,r,0,cnt,++acnt);
it1=S.lower_bound(l);
if(*it1>r)ans[acnt]=i-las[*--it1];
}
}
sort(q+1,q+cnt+1);
solve(1,cnt);
for(i=1;i<=acnt;i++)
printf("%lld\n",ans[i]);
}