NOI2017

不知道能改出来几道题。有一种自己码力真的太烂的强烈感觉。

最近总是头痛,晕乎乎的,状态不好。

感觉天天都在卡常骗分……

先给个Achen题解链接:http://www.cnblogs.com/Achenchen/p/8921880.html

 

D1T1 integer

没压位的68分代码:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=1e6+7,maxm=11e7+107;
int n,W;

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

int sum[maxm],ql,qr,qx;
void ud(int pos) {sum[pos]=sum[pos<<1]+sum[pos<<1|1];}
void pd(int pos,int l,int r) {
//	if(sum[pos]!=0&&sum[pos]!=r-l+1) return;
	if(sum[pos<<1]+sum[pos<<1|1]==sum[pos]) return;
	int mid=(l+r)>>1;
	if(sum[pos]==0) sum[pos<<1]=sum[pos<<1|1]=0;
	else sum[pos<<1]=mid-l+1,sum[pos<<1|1]=r-mid;
}

int q(int pos,int l,int r) {
	if(!sum[pos]) return 0;
	if(sum[pos]==r-l+1) return 1;
	int mid=(l+r)>>1;
	pd(pos,l,r);
	if(ql<=mid) return q(pos<<1,l,mid);
	else return q(pos<<1|1,mid+1,r);
}
/*
void debug() {
	printf("debug:\n");
	For(i,1,20) ql=qr=i,printf("%d ",q(1,1,W));
	printf("\n");
}
*/
void chge(int pos,int l,int r) {
	if(l==r) {
		sum[pos]+=qx;
		return;
	}
	int mid=(l+r)>>1;
	pd(pos,l,r);
	if(ql<=mid) chge(pos<<1,l,mid);
	else chge(pos<<1|1,mid+1,r);
	ud(pos);
}

int find(int pos,int l,int r) {
	if(qx==1&&sum[pos]==(r-l+1)) return 0;
	if(qx==-1&&sum[pos]==0) return 0;
	if(l==r) return l;
	int mid=(l+r)>>1,rs=0;
	pd(pos,l,r);
	if(ql<=mid) rs=find(pos<<1,l,mid);
	if(!rs) rs=find(pos<<1|1,mid+1,r);
	return rs;
}

void rml(int pos,int l,int r) {
	if(l>=ql&&r<=qr) {
		if(qx==1) sum[pos]=0;
		else sum[pos]=(r-l+1);
		return;
	}
	int mid=(l+r)>>1;
	pd(pos,l,r);
	if(ql<=mid) rml(pos<<1,l,mid);
	if(qr>mid) rml(pos<<1|1,mid+1,r);
	ud(pos);
}

void get_chge(ll x,int pos) {
	int p;
	For(i,0,31) {
		if(x&1) {
			ql=pos; qr=W;
			p=find(1,1,W);
			ql=qr=p;
			chge(1,1,W);
//			printf("chge: %d , %d\n",p,qx);
//			debug();
			if(p!=pos) {
				ql=pos; qr=p-1;
				rml(1,1,W);
//				printf("rml: %d~%d , %d\n",ql,qr,qx==1? 0:1);
//				debug();
			}
		}
		x>>=1; pos++;
	}
}
	
int main() {
	freopen("integer.in","r",stdin);
	freopen("integer.out","w",stdout);
	int op; ll x,y;
	read(n); W=n+100;
	read(op); read(op); if(op==4) W=30*n+100;
	read(op);
	For(i,1,n) {
		read(op);
		read(x);
		if(op==1) {
			read(y); y++;
			if(x>0) qx=1;
			else qx=-1,x=-x;
			get_chge(x,y);
		}
		else {
			ql=qr=x+1;
			printf("%d\n",q(1,1,W));
		}
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

压位的满分代码:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
#define lc pos<<1
#define rc pos<<1|1
const int maxn=1e6+107,W=30,U=(1<<30)-1;
int n,TOT;

char cc; ll ff;
template<typename T>void read(T& aa) {
    aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

ll sum[4*maxn],num[4*maxn],ql,qr,qx,qy,qo;
void ud(int pos) {sum[pos]=sum[lc]+sum[rc];}
int cnt(ll x) {int rs=0;while(x) x-=x&-x,++rs;return rs;}

int pd(int pos,int l,int r) {
	int mid=(l+r)>>1;
	if(sum[pos]==sum[lc]+sum[rc]) return mid;
	if(sum[pos]==0) sum[lc]=sum[rc]=0;
	else if(sum[pos]==(r-l+1)*W) sum[lc]=(mid-l+1)*W,sum[rc]=(r-mid)*W;
	return mid;
}

void fchge(int pos,int l,int r,int x) {
	if(l==r) {
		if(sum[pos]==W) num[pos]=U;else if(sum[pos]==0) num[pos]=0;
		num[pos]=num[pos]+x;
		sum[pos]=cnt(num[pos]);
		return;
	}
	int mid=pd(pos,l,r);
	if(x==1) {
		if(sum[lc]!=(mid-l+1)*W) fchge(lc,l,mid,x);
		else sum[lc]=0,fchge(rc,mid+1,r,x);
	}
	else {
		if(sum[lc]!=0) fchge(lc,l,mid,x);
		else sum[lc]=(mid-l+1)*W,fchge(rc,mid+1,r,x);
	}
	ud(pos);
}

void chge(int pos,int l,int r) {
	if(l==r) {
		if(sum[pos]==W) num[pos]=U;else if(sum[pos]==0) num[pos]=0;
		qo=0; num[pos]=num[pos]+qx;
		if(num[pos]>U) num[pos]-=(U+1),qo=1;
		if(num[pos]<0) num[pos]+=(U+1),qo=-1;
		sum[pos]=cnt(num[pos]);
		return;
	}
	int mid=pd(pos,l,r);
	if(ql<=mid) {
		chge(pos<<1,l,mid);
		if(qo==1) {
			if(sum[rc]!=(r-mid)*W) fchge(rc,mid+1,r,1),qo=0;
			else sum[rc]=0;
		}
		else if(qo==-1) {
			if(sum[rc]) fchge(rc,mid+1,r,-1),qo=0;
			else sum[rc]=(r-mid)*W;
		}
	}
	else chge(pos<<1|1,mid+1,r);
	ud(pos);
}

int q(int pos,int l,int r) {
	if(l==r) {
		if(sum[pos]==W) num[pos]=U;else if(sum[pos]==0) num[pos]=0;
		return num[pos];
	}
	int mid=pd(pos,l,r);
	if(ql<=mid) return q(pos<<1,l,mid);
	return q(pos<<1|1,mid+1,r);
}
		

void get_chge(ll x,ll y) {
	ll ld;
	if(y<0) qy=-1,y=-y;
	else qy=1;
	ql=qr=(x+W-1)/W;
	ld=(ql-1)*W+1;
	y<<=(x-ld);
	qx=qy*(y&U);
	if(qx!=0) chge(1,1,TOT);
	y>>=W;
	while(y) {
		ql++; qr++; qx=qy*y;
		chge(1,1,TOT);
		y>>=W;
	}
}

int get_q(int x) {
	ll ld;
	ql=qr=(x+W-1)/W;
	ld=(ql-1)*W+1;
	ll rs=q(1,1,TOT);
	rs>>=(x-ld);
	return rs&1;
}
	
int main() {
    freopen("integer.in","r",stdin);
    freopen("integer.out","w",stdout);
    int op; ll x,y;
    read(n); read(x); read(x); read(x); TOT=n+100;
    For(i,1,n) {
    	read(op); read(x); 
    	if(op==1) {
    		read(y);
    		get_chge(++y,x);
    	}
    	else printf("%d\n",get_q(++x));
    }
    fclose(stdin); fclose(stdout);
    return 0;
}

D1T2 queue

双hash取模只有40,hash unsigned long long自然溢出有60

分得满得用Trie……

对于trie里面的每个点处理出一个后继指针表示其删掉当前字符串的第一个字符它会跳到哪一个点

我们可以发现,如果我新建一个节点p,表示串s[1~len],那么之前trie中一定存在s[2~len]

所以每次新建点的时候算这个后继指针是不会出问题的

40分的双hash

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=3e5+7,maxs=1e7+7,maxt=57;
const ll Bs=7,M1=998244353,M2=1e9+7,mod=998244353;
ll n,m,a[maxn],b[maxs],ld[maxn],rd[maxn],W=50;
char s[maxs];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

ll mo1(ll x) {while(x>=M1) x-=M1;return x;}
ll mo2(ll x) {while(x>=M2) x-=M2;return x;}

struct T{
	ll x,y;
	T(){}
	T(ll x,ll y):x(x),y(y){}
	T operator + (const T& b) const{return T(mo1(x+b.x),mo2(y+b.y));}
	T operator - (const T& b) const{return T(mo1(x-b.x+M1),mo2(y-b.y+M2));}
	T operator * (const T& b) const{return T(x*b.x%M1,y*b.y%M2);}
	bool operator < (const T& b) const{return x==b.x? y<b.y:x<b.x;}
}mi[maxt],D[maxt];

map<T,int> G[maxt];
/*
void chge(int x,int y,int o) {
	int lenx=1,leny,pos;
	T X=T(0,0),Y;
	while(x&&lenx<W) {
		X=X+T(a[x],a[x])*mi[lenx-1];
		leny=1; pos=y; Y=T(0,0);
		while(pos&&lenx+leny<=W) {
			Y=Y*mi[1]+T(a[pos],a[pos]);
			G[lenx+leny][X*mi[leny]+Y]+=o;
			pos=rd[pos]; leny++;
		}
		x=ld[x]; lenx++;
	}
}
*/
void chge(int x,int y,int o) {
	int lenx=1,leny=1,r;
	D[0]=T(0,0); T X=T(0,0);
	while(y&&leny<W) {
		D[leny]=D[leny-1]*mi[1]+T(a[y],a[y]);
		y=rd[y]; leny++;
	}
	leny--;
	while(x&&lenx<W) {
		X=X+T(a[x],a[x])*mi[lenx-1];
		r=min((int)W-lenx,leny);
		For(i,1,r) 
			G[lenx+i][X*mi[i]+D[i]]+=o;
		x=ld[x]; lenx++;
	}
}

ll get_ans(int k) {
	int len=strlen(s+1);
	For(i,1,len) b[i]=s[i]-'0';
	T now=T(0,0); ll rs=1;
	For(i,1,k) now=now*mi[1]+T(b[i],b[i]);
	For(i,1,len-k+1) {
		rs=rs*G[k][now]%mod;
		if(rs==0) return rs;
		now=now*mi[1]+T(b[i+k],b[i+k]);
		now=now-T(b[i],b[i])*mi[k];
	}
	return rs;
}

int main() {
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	read(n); read(m);
	mi[0]=T(1,1); mi[1]=T(Bs,Bs);
	For(i,2,W) mi[i]=mi[i-1]*mi[1];
	For(i,1,n) read(a[i]),G[1][T(a[i],a[i])]++;
	int op,x,y;
	For(i,1,m) {
		read(op);
//		cerr<<i<<": "<<clock()<<"\n";
		if(op==1) {
			read(x); read(y);
			rd[x]=y; ld[y]=x;
			chge(x,y,1);
		}
		else if(op==2) {
			read(x); y=rd[x];
			rd[x]=0; ld[y]=0;
			chge(x,y,-1);
		}
		else {
			scanf("%s",s+1);
			read(x);
			printf("%lld\n",get_ans(x));
		}
	}
//	cerr<<clock()<<"\n";
	fclose(stdin); fclose(stdout);
	return 0;
}

60分的hash

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define ll unsigned long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=3e5+7,maxs=1e7+7,maxt=57;
const ll Bs=7,mod=998244353;
ll n,m,a[maxn],b[maxs],ld[maxn],rd[maxn],W=50;
char s[maxs];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

ll mi[maxt],D[maxt];

map<ll,int> G[maxt];

void chge(int x,int y,int o) {
	int lenx=1,leny=1,r;
	D[0]=0; ll X=0;
	while(y&&leny<W) {
		D[leny]=D[leny-1]*mi[1]+a[y];
		y=rd[y]; leny++;
	}
	leny--;
	while(x&&lenx<W) {
		X=X+a[x]*mi[lenx-1];
		r=min((int)W-lenx,leny);
		For(i,1,r) 
			G[lenx+i][X*mi[i]+D[i]]+=o;
		x=ld[x]; lenx++;
	}
}

ll get_ans(int k) {
	int len=strlen(s+1);
	For(i,1,len) b[i]=s[i]-'0';
	ll now=0; ll rs=1;
	For(i,1,k) now=now*mi[1]+b[i];
	For(i,1,len-k+1) {
		rs=rs*G[k][now]%mod;
		if(rs==0) return rs;
		now=now*mi[1]+b[i+k];
		now=now-b[i]*mi[k];
	}
	return rs;
}

int main() {
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	read(n); read(m);
	mi[0]=1; mi[1]=Bs;
	For(i,2,W) mi[i]=mi[i-1]*mi[1];
	For(i,1,n) read(a[i]),G[1][a[i]]++;
	int op,x,y;
	For(i,1,m) {
		read(op);
//		cerr<<i<<": "<<clock()<<"\n";
		if(op==1) {
			read(x); read(y);
			rd[x]=y; ld[y]=x;
			chge(x,y,1);
		}
		else if(op==2) {
			read(x); y=rd[x];
			rd[x]=0; ld[y]=0;
			chge(x,y,-1);
		}
		else {
			scanf("%s",s+1);
			read(x);
			printf("%lld\n",get_ans(x));
		}
	}
//	cerr<<clock()<<"\n";
	fclose(stdin); fclose(stdout);
	return 0;
}

Trie

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define ll unsigned long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=1e6+7,maxs=2e7+7,maxt=57;
const ll mod=998244353;
ll n,m,a[maxn],b[maxs],ld[maxn],rd[maxn],W=50,tot=6;
char s[maxs];
int son[maxs][7],sum[maxs],to[maxs];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

void chge(int x,int y,int o) {
	int lenx,leny,p,now,pos;
	for(p=x,lenx=1;p&&lenx<W;++lenx,p=ld[p]) {
		now=0;
		for(pos=p;pos;pos=rd[pos]) {
			if(!son[now][a[pos]]) {
				son[now][a[pos]]=++tot;
				to[tot]=son[to[now]][a[pos]];
			}
			now=son[now][a[pos]];
		}
		for(pos=y,leny=1;pos&&leny+lenx<=W;++leny,pos=rd[pos]) {
			if(!son[now][a[pos]]) {
				son[now][a[pos]]=++tot;
				to[tot]=son[to[now]][a[pos]];
			}
			now=son[now][a[pos]];
			sum[now]+=o;
		}
	}
}

ll get_ans(int k) {
	int len=strlen(s+1),now=0; ll rs=1;
	For(i,1,len) b[i]=s[i]-'0';
	for(int i=1;i<=k;++i) {
		now=son[now][b[i]];
		if(now==0) return 0;
	}
	for(int i=k;i<=len&&rs;now=son[to[now]][b[++i]]) rs=rs*(ll)sum[now]%mod;
	return rs;
}

int main() {
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	read(n); read(m);
	For(i,1,6) son[0][i]=i;
	For(i,1,n) read(a[i]),sum[a[i]]++;
	int op,x,y;
	For(i,1,m) {
		read(op);
		if(op==1) {
			read(x); read(y);
			chge(x,y,1);
			rd[x]=y; ld[y]=x;
		}
		else if(op==2) {
			read(x); y=rd[x];
			rd[x]=0; ld[y]=0;
			chge(x,y,-1);
		}
		else {
			scanf("%s",s+1);
			read(x);
			printf("%lld\n",get_ans(x));
		}
	}
	return 0;
}

 

D1T3

重点来写这道题的题解。谁让我被一篇题解坑了一晚上呢。

如果我们能计算出$s_i$表示最大子矩形$\leq i$的概率,那么$s_k - s_{k-1}$就是答案

如果我们现在要求$s_k$:

首先我们发现,泳池高度恒定,1001,而$k \leq 1000$,那么相当于泳池的高度可以看作无穷。

我们思考,如果我设$f_i$表示前$i$列最大合法子矩阵$\leq k$的概率,那么$f_n$就是答案。

怎么求$f_n$呢。

我们设$g_{i,j}$表示连续$j$列中靠泳池边的$i$行都是安全的,其他未知,并且这$j$列的最大合法子矩阵$\leq k$的概率

如果当前要求$f_i$,我们可以枚举靠泳池边的那一行,最靠右的不安全的格子在哪里,这个格子一定把这$j$列分成两半,只要这两半的最大合法子矩阵分别都$\leq k$就可以了

$f_i = \sum\limits_{j=0}^{min(i-1,k)} g_{1,j} (1 - q) f_{i-j-1}$。

注意,当$i \leq k$的时候,靠泳池边的那一行有可能没有不安全的格子,所以还要加上这种情况的概率。

我们发现这是常系数线性递推,还可以NTT优化多项式取模。所以我们现在只用考虑怎么算$g$。

设$h_{i,j}$表示连续$j$列中,靠泳池边的$i$行都是安全的,其他未知,但是$(i+1,j)$一定是危险的,并且这$j$列的最大合法子矩阵$\leq k$的概率。

那么有:

$ g_{i,j}=\sum\limits_{k=0}^{j}h_{i,k}g_{i+1,j-k} $

$h_{i,j}=\sum\limits_{k=0}^{j-1}h_{i,k}g_{i+1,j-k-1}q^i(1-q)  $

边界是:

$ g_{k,1}=q^k(1-q)$

$g_{i,0}=1$

$h_{i,0}=1$

因为对于$i$行,我们只需要算$\lfloor \frac{k}{i} \rfloor$列就可以了,所以复杂度是$k^2$的。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=2000+7;
const ll mod=998244353;
ll n,K,nk,q,mi1[maxn],mi2[maxn],h[maxn][maxn],g[maxn][maxn],a[maxn];
ll ans[maxn];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

void mo(ll& x){if(x>=mod) x-=mod;}

ll qp(ll x,ll k) {
	ll rs=1;
	while(k) {
		if(k&1) rs=rs*x%mod;
		k>>=1; x=x*x%mod;
	}
	return rs;
}

struct Node{
	ll p[maxn];
	Node(){memset(p,0,sizeof(p));}
	Node operator * (const Node& b) {
		Node o;
		memset(o.p,0,sizeof(o.p));
		For(i,0,nk) For(j,0,nk) {
			o.p[i+j]+=p[i]*b.p[j]%mod;
			mo(o.p[i+j]);
		}
		Rep(i,2*nk,nk+1) if(o.p[i]) {
			For(j,1,nk+1) {
				o.p[i-j]+=a[j]*o.p[i]%mod;
				mo(o.p[i-j]);
			}
			o.p[i]=0;
		}
		return o;
	}
	void print() {
		printf("print:\n");
		For(i,0,nk) printf("%lld ",p[i]);
		printf("\n");
	}
}rs,X;

void qpp(ll n) {
	memset(X.p,0,sizeof(X.p));
	memset(rs.p,0,sizeof(rs.p));
	rs.p[0]=1; X.p[1]=1;
	while(n) {
		if(n&1) rs=rs*X;
		n>>=1; X=X*X;
//		X.print();
	}
}

ll get_ans(ll n,ll k) {
	if(!k) return qp(mi2[1],n);
	ll m; nk=k;
	memset(g,0,sizeof(g));
	memset(h,0,sizeof(h));
	memset(ans,0,sizeof(ans));
	g[k][1]=h[k][1]=mi1[k]*mi2[1]%mod;
	g[k][0]=h[k][0]=1;
	Rep(i,k-1,1) {
		g[i][0]=h[i][0]=1;
		m=k/i;
		For(j,1,m) {
			For(l,0,j-1) 
				h[i][j]+=h[i][l]*g[i+1][j-l-1]%mod*mi1[i]%mod*mi2[1]%mod;
			h[i][j]%=mod;
			For(l,0,j) 
				g[i][j]+=h[i][l]*g[i+1][j-l]%mod;
			g[i][j]%=mod;
		}
	}
	For(i,1,k+1) a[i]=g[1][i-1]*mi2[1]%mod;
//	For(i,1,k) printf("%lld ",a[i]);
//	printf("\n");
	ans[0]=1;
//	printf("%lld ",ans[0]);
	For(i,1,k) {
		ans[i]=g[1][i];
		For(j,1,i) ans[i]+=ans[i-j]*a[j]%mod;
		ans[i]%=mod;
//		printf("%lld ",ans[i]);
	}
//	printf("\n");
	if(n<=k) return ans[n];
	qpp(n);
	ll tot=0;
	For(i,0,k) tot+=ans[i]*rs.p[i]%mod;
//	printf("tot: %lld\n",tot%mod);
	return tot%mod; 
}

int main() {
	read(n); read(K);
	ll x,y;
	read(x); read(y);
	q=x*qp(y,mod-2)%mod;
	mi1[0]=mi2[0]=1;
	mi1[1]=q; mi2[1]=(1-q+mod)%mod;
	For(i,2,2*K+1) {
		mi1[i]=mi1[i-1]*mi1[1]%mod;
		mi2[i]=mi2[i-1]*mi2[i]%mod;
	}
	printf("%lld\n",(get_ans(n,K)-get_ans(n,K-1)+mod)%mod);
	return 0;
}

 

D2T1 game

论这道题今年考没昨年7月考的分高是什么样的体验

2-SAT简单题?对于x就直接2^d枚举是不是A就可以了

第一次写2-SAT,学了半下午,debug了半下午+一晚上,感觉慢慢适应了长时间debug但是de不出来的感觉

2-SAT讲得很好的一个博客:https://blog.csdn.net/jarjingx/article/details/8521690

放几个小样例在这里吧,output自己观察:

Sample Input1

2 1
xc
4
2 B 2 A
2 A 1 C
2 C 2 C
2 B 1 A

Sample Input2

5 0
bcbbb
10
1 B 1 C
3 C 1 C
2 B 5 A
1 C 1 C
2 A 5 A
3 A 1 C
2 B 1 C
3 A 1 B
1 B 4 B
1 B 4 A
//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=5e5+7,maxm=2e6+7;
int n,m,d,v[maxn],p[maxn],tot;
char s[maxn];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

struct Node{
	int x,y,a,b;
	Node(){}
	Node(int x,int y,int a,int b):x(x),y(y),a(a),b(b){}
}node[maxm];


int fir[maxn],nxt[2*maxm],to[2*maxm],e=1;
void add(int x,int y) {
//	printf("add:%d->%d\n",x,y);
	to[++e]=y;nxt[e]=fir[x];fir[x]=e;
}

int FIR[maxn],NXT[2*maxm],TO[2*maxm],ind[maxn],E=0;
void ADD(int x,int y) {
//	printf("ADD:%d->%d\n",x,y);
	TO[++E]=y;NXT[E]=FIR[x];FIR[x]=E; ++ind[y];
}

int ok(int x,int y) {
	int rs=0;
	For(i,1,3) if(v[x]!=i) {
		rs++;
		if(i==y) return rs;
	}
	return 0;
}

int fok(int x,int y) {
	For(i,1,3) if(v[x]!=i) {
		y--;
		if(y==0) return i;
	}
	return 0;
}

int id(int x,int y) {return (x-1)*2+y;}

int bel[maxn];
bool del(int x,int y) {
	if(bel[x]==y) return 0;
	if(v[x]==y) return 1;
	bel[x]=6-y-v[x];
	return 1;
}

int zz[maxn],dfn[maxn],low[maxn],f[maxn],dfn_clock,toth,t;
bool vis[maxn];
void tj(int pos) {
	dfn[pos]=low[pos]=++dfn_clock; zz[++t]=pos; vis[pos]=1;
	int y,z; 
	for(y=fir[pos];y;y=nxt[y]) {
		if(dfn[z=to[y]]) {if(vis[z]) low[pos]=min(low[pos],dfn[z]);}
		else tj(z),low[pos]=min(low[pos],low[z]);
	}
	if(low[pos]==dfn[pos]) {
		++toth;
		while(zz[t]!=pos) vis[zz[t]]=0,f[zz[t--]]=toth;
		vis[zz[t]]=0; f[zz[t--]]=toth;
	}
}

int mark[maxn],atk[maxn];
void tp() {
	int s=1,t=0,x,y,z;
	For(i,1,toth) if(!ind[i]) zz[++t]=i;
	while(s<=t) {
		x=zz[s++];
		mark[atk[x]]=mark[x]^1;
		for(y=FIR[x];y;y=NXT[y]) {
			z=TO[y];
			if(mark[x]) mark[z]=1;
			if((--ind[z])==0) zz[++t]=z;
		}
	}
	For(i,1,n) if(!bel[i]){
		if(mark[f[i<<1]]) bel[i]=fok(i,1);
		else bel[i]=fok(i,2);
	}
	For(i,1,n) printf("%c",'A'+bel[i]-1);
	printf("\n");
}

bool check() {
	int x,y,z,a,b; e=1;E=0;
	For(i,1,2*n) dfn[i]=fir[i]=FIR[i]=mark[i]=0;
	For(i,1,m) {
		x=node[i].x; y=node[i].y;
		a=node[i].a; b=node[i].b;
		if(x==y) {
			if(a==b) continue;
			else if(a!=b&&!del(x,a)) return 0;
		}
		else {
			if(!ok(y,b)&&!del(x,a)) return 0;
			a=ok(x,a); b=ok(y,b);
			if(a&&b) {
				add(id(y,b),id(x,a));
				add(id(x,3-a),id(y,3-b));
			}
		}
	}
	For(i,1,n) if(bel[i]){
		x=ok(i,bel[i]);
		y=3-x;
		x=id(i,x); y=id(i,y);
		add(x,y);
	}
	For(i,1,2*n) if(!dfn[i]) 
		t=0,tj(i);
	For(i,1,n) {
		x=f[i*2-1]; y=f[i*2];
		if(x==y) return 0;
		atk[x]=y; atk[y]=x;
	}
	For(i,1,2*n) {
		x=f[i];
		for(y=fir[i];y;y=nxt[y]) {
			if((z=f[to[y]])==x) continue;
			ADD(x,z);
		}
	}
	tp();
	return 1;
}

bool solve() {
	tot=(1<<d)-1;
	For(r,0,tot) {
		For(i,1,n) bel[i]=0;
		For(i,1,d) {
			if((r>>(i-1))&1) v[p[i]]=1;
			else v[p[i]]=3,bel[p[i]]=1;
		}
		if(check()) return 1;
	}
	return 0;
}

int main() {
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	read(n); read(d); int x,y,a,b;
	scanf("%s",s+1);
	For(i,1,n) {
		if(s[i]!='x') v[i]=s[i]-'a'+1;
		else p[++tot]=i;
	}
	read(m);
	For(i,1,m) {
		read(x);
		scanf("%s",s+1);
		a=s[1]-'A'+1;
		read(y);
		scanf("%s",s+1);
		b=s[1]-'A'+1;
		node[i]=Node(x,y,a,b);
	}
	if(!solve()) printf("-1\n");
	return 0;
}

D2T2

贪心。首先我们考虑如果天数最多的时候的答案。

如果我们知道了时间是i天的答案,那么我们可以直接在所取的里面贪心选最小的几个不要,算i-1天的答案。

因为如果i天答案中能取的一个子集,如果个数<=(i-1)*m,肯定i-1天也可以取。

那么我们怎么求天数最多(假如是p天)的答案呢。

把每种蔬菜拆成两份,前c-1个价值为a,最后一个价值为a+s(按变质的顺序)放入优先队列中,依次取出来放入还能放的时间最大的地方即可。

这个可以用并查集。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=1e6+7,INF=1e7;
ll n,m,k,ask[maxn],maxp,f[maxn],TOT,nowans,ans[maxn];

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

struct Node{
	ll v,sum,r,d;
	Node(ll v,ll sum,ll r,ll d):v(v),sum(sum),r(r),d(d){}
	bool operator < (const Node& b) const{return v<b.v;}
};
priority_queue<Node>G;
multiset<ll> H;
multiset<ll>::iterator it;

int find(int x) {return x==f[x]? x:f[x]=find(f[x]);}

bool insert(ll d,ll v) {
	ll pos=find(min(d,maxp)*m);
	if(pos) {
		++TOT;
		f[pos]=find(pos-1);
		H.insert(v);
		nowans+=v;
		return 1;
	}
	else return 0;
}

int main() {
	freopen("vegetables.in","r",stdin);
	freopen("vegetables.out","w",stdout);
	read(n); read(m); read(k);
	ll a,s,c,x,v,sum,r,d;
	For(i,1,n) {
		read(a); read(s); read(c); read(x);
		if(c>1) {
			v=a; sum=c-1; r=x; d=0;
			G.push(Node(v,sum,r,d));
		}
		v=a+s; sum=1; r=0; if(x) d=(c-1)/x+1; else d=INF;
		G.push(Node(v,sum,r,d));
	}
	For(i,1,k) read(ask[i]),maxp=max(maxp,ask[i]);
	For(i,1,maxp*m+1) f[i]=i;
	while(!G.empty()) {
		Node o=G.top();
		v=o.v; sum=o.sum; r=o.r; d=o.d;
		G.pop();
		if(d!=0) insert(d,v);
		else {
			while(sum) {
				if(r) d=(sum-1)/r+1; else d=INF;
				if(!insert(d,v)) break;
				--sum;
			}
		}
	}
	Rep(i,maxp,1) {
		while(TOT>i*m&&TOT) {
			it=H.begin();
			nowans-=*it;
			H.erase(it);
			TOT--;
		}
		ans[i]=nowans;
	}
	For(i,1,k) printf("%lld\n",ans[ask[i]]);
	return 0;
}

 

gi,jhi,j=k=0jhi,kgi+1,jk=k=0j1hi,kgi+1,jk1qi(1q)

posted @ 2018-04-15 12:20  shixinyi  阅读(325)  评论(0编辑  收藏  举报