这是一个句子测试

12
10
2015
0

BZOJ1901Dynamic Rankings

【题目简介】

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

 

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

 

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

 

Source

【题解】

假如不带修改,那么就是可持久化线段树的模板题。

那么窝萌注意到:可持久化线段树维护的其实是一个片段和一样的东西。

对于片段和的维护,如果不带修改,那么就可以直接用数组,否则就需要树状数组。

那么窝萌是不是可以用树状数组的方式来维护可持久化线段树呢?

显然是可以的,只要把每棵可持久化线段树看作树状数组上的点就可以了。

对于修改,每次都要改logn棵树;查询同样需要logn棵树的值相加。

所以时空复杂度都是nlogn2的。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=20010;
int A[M],a[M],L[100],R[100],op[M][5],cnt,_n,n,m,i;
struct node{int l,r,w;}tree[M*100];
bool cmp(int i,int j){return A[i]<A[j];}
void insert(int x,int l,int r,int p,int t){
	tree[p].w+=t;
	if (l==r)return;
	int mid=l+r>>1;
	if (x<=mid){
		if (!tree[p].l)tree[p].l=++cnt;
		insert(x,l,mid,tree[p].l,t);
	}else{
		if (!tree[p].r)tree[p].r=++cnt;
		insert(x,mid+1,r,tree[p].r,t);
	}
}
void update(int x,int p,int q){
	for (;x<=n;x+=x&-x)insert(p,1,_n,x,q);
}
int query(int l,int r,int k){
	if (l==r)return l;
	int i,x=0,y=0;
	for (i=1;i<=L[0];i++)x+=tree[tree[L[i]].l].w;
	for (i=1;i<=R[0];i++)y+=tree[tree[R[i]].l].w;
	int mid=l+r>>1;
	if (y-x>=k){
		for (i=1;i<=L[0];i++)L[i]=tree[L[i]].l;
		for (i=1;i<=R[0];i++)R[i]=tree[R[i]].l;
		return query(l,mid,k);
	}else{
		for (i=1;i<=L[0];i++)L[i]=tree[L[i]].r;
		for (i=1;i<=R[0];i++)R[i]=tree[R[i]].r;
		return query(mid+1,r,k-y+x);
	}
}
int Query(int l,int r,int k){
	L[0]=0;for (int i=l-1;i;i-=i&-i)L[++L[0]]=i;
	R[0]=0;for (int i=r;i;i-=i&-i)R[++R[0]]=i;
	return query(1,_n,k);
}
int main(){
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)scanf("%d",&a[i]),A[i]=a[i];
	_n=n;
	for (i=1;i<=m;i++){
		char s[5];
		scanf("%s",s);
		if (s[0]=='Q'){
			op[i][0]=0;
			scanf("%d%d%d",&op[i][1],&op[i][2],&op[i][3]);
		}else{
			op[i][0]=1;
			scanf("%d%d",&op[i][1],&op[i][2]);
			A[++_n]=op[i][2];
		}
	}
	sort(A+1,A+_n+1),cnt=n;
	_n=unique(A+1,A+_n+1)-A-1;
	for (i=1;i<=n;i++)a[i]=lower_bound(A+1,A+_n+1,a[i])-A;
	for (i=1;i<=m;i++)if (op[i][0])op[i][2]=lower_bound(A+1,A+_n+1,op[i][2])-A;
	for (i=1;i<=n;i++)update(i,a[i],1);
	for (i=1;i<=m;i++)
		if (op[i][0]){
			update(op[i][1],a[op[i][1]],-1);
			a[op[i][1]]=op[i][2];
			update(op[i][1],a[op[i][1]],1);
		}else printf("%d\n",A[Query(op[i][1],op[i][2],op[i][3])]);
}
Category: 蒟蒻的BZOJ刷题记 | Tags:
12
8
2015
0

Contest20151207滚粗记

听说这是JSOIDay3

膜了贵省的题目,感到不明觉厉。

Orz NiroBC 210

Orz Chrysanthemum 130

Orz drc神犇(SB) 0

T1

看到期望慌了,先吔点东西压压惊。

好吧让窝萌推一下。

对于一个女性,列表中总共有cnt个对象,选中第i个对象的概率:

[tex]\sum\limits_{j = 0}^{ + \infty } {p*{{(1 - p)}^{i + cnt*j - 1}}}[/tex]

显然这是一个等比数列,列出求和公式:

[tex]\frac{{1 - {{(1 - p)}^j}}}{{1 - {{(1 - p)}^{cnt}}}}*p*{(1 - p)^{i - 1}}[/tex]

当j趋向于正无穷时(1-p)j趋向于0,那么公式就变成了:

[tex]\frac{{p*{{(1 - p)}^{i - 1}}}}{{1 - {{(1 - p)}^{cnt}}}}[/tex]

接着只要倒着扫一遍,然后将概率一一插入树状数组并询问就可以辣!

什么我居然丢了这送的40分。

T2

看到题目慌了,这不是NiroBC出的Gold_7穿裙子?

让窝萌来YY一个最小割小费用最大流吧。

哦好像是错的。愉快爆蛋。

我去正解是贪心。。。贪心怎会没有反例

考虑将x0放入x,y0放入y,其中b[x]>b[y],Out[x0]<Out[y0]。

如果把x0放入y,y0放入x(假设x0和y0都是可以放进x和y的)。

ans1=(In[x]-Out[x0])*b[x]+(In[y]-Out[y0])*b[y]

ans2=(In[x]-Out[y0])*b[x]+(In[y]-Out[x0])*b[y]

ans1-ans2=(Out[y0]-Out[x0])*(b[x]-b[y])<0

显然按b排序,取能放下的最大的,一定不存在更优解。

所以贪心好像没有反例。

那么用数据结构维护一下就可以辣!

(窝用二分+线段树O(nlogn2)然而Gold_7用set既快又短。。。)

T3

看到计蒜几何慌了,让我先打个20分压压惊。

诶好像40分也很好拿吖。

诶好像这只是一道码农题+乱搞题。

拒绝做这种恶心题。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=1000010;
int n,m,i,j,x,y,edgenum;
double p,ans;
int head[M],vet[M],next[M],a[M];
double tree[M];
double mi[M];
void addedge(int x,int y){
	vet[++edgenum]=y;
	next[edgenum]=head[x];
	head[x]=edgenum;
}
int lowbit(int x){return x&(-x);}
double query(int x){
	double ans=0;
	while (x){
		ans+=tree[x];
		x-=lowbit(x);
	}
	return ans;
}
void update(int x,double t){
	while (x<=n){
		tree[x]+=t;
		x+=lowbit(x);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	scanf("%lf",&p);
	for (i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		addedge(x,y);
	}
	mi[0]=1;
	for (i=1;i<=n;i++)mi[i]=mi[i-1]*(1-p);
	for (i=n;i>=1;i--){
		int cnt=0;
		for (int e=head[i];e;e=next[e])a[++cnt]=vet[e];
		sort(a+1,a+cnt+1);
		for (j=cnt;j>=1;j--)ans+=p*mi[j-1]/(1-mi[cnt])*query(a[j]-1),update(a[j],p*mi[j-1]/(1-mi[cnt]));
	}
	printf("%.2lf",ans);
}
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
int n,i,flag;
ll ans;
int tree[500010];
struct shit{ll in;ll out;ll imp;}a[500010];
bool cmp(shit i,shit j){return i.imp>j.imp;}
void update(int x,int l,int r,int p,int cmp){
	tree[p]+=cmp;
	if (l==r)return;
	int mid=l+r>>1;
	if (x<=mid)update(x,l,mid,p<<1,cmp);else update(x,mid+1,r,p<<1|1,cmp);
}
int search(int x,int y,int l,int r,int p){
	if (x==l&&y==r)return tree[p];
	int mid=l+r>>1;
	if (y<=mid)return search(x,y,l,mid,p<<1);
		else if (x>mid) return search(x,y,mid+1,r,p<<1|1);
			else return search(x,mid,l,mid,p<<1)+search(mid+1,y,mid+1,r,p<<1|1);
}
int main(){
	scanf("%d",&n);
	for (i=1;i<=n;i++)scanf("%d%d%d",&a[i].out,&a[i].in,&a[i].imp);
	sort(a+1,a+n+1,cmp);
	for (i=1;i<=n;i++)update(a[i].out,1,10000,1,1);
	for (i=1;i<=n;i++){
		if (a[i].in==1){ans+=a[i].in*a[i].imp;continue;}
		int cnt=0;
		int l=1,r=a[i].in-1;
		while (l+1<r){
			int mid=l+r>>1;
			if (search(mid,a[i].in-1,1,10000,1))l=mid;else r=mid;
		}
		if (search(r,a[i].in-1,1,10000,1))cnt=r;else if (search(l,a[i].in-1,1,10000,1))cnt=l;else ans+=a[i].in*a[i].imp;
		if (cnt)update(cnt,1,10000,1,-1),ans+=(a[i].in-cnt)*a[i].imp;
	}
	printf("%lld\n",ans);
}
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double pi=3.1415926535;
int n,i,ans,ans1,flag[100];
double stx[100],sty[100],edx[100],edy[100];
double X1,Y1,X2,Y2,ang,len,k;
int check(int x){
	if (stx[x]==edx[x]){if (k*stx[x]>=sty[x]&&k*stx[x]<=edy[x]||k*stx[x]>=edy[x]&&k*stx[x]<=sty[x])return 0;else return 1;}
	double k1=(edy[x]-sty[x])/(edx[x]-stx[x]);
	double b=sty[x]-stx[x]*k1;
	if (k==k1)return 1;
	double xx=b/(k-k1);
	if (xx>=stx[x]&&xx<=edx[x])return 0;else return 1;
}
int main(){
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	scanf("%d%lf%lf",&n,&ang,&len);
	for (i=1;i<=n;i++){
		scanf("%lf%lf%lf%lf%d",&stx[i],&sty[i],&edx[i],&edy[i],&flag[i]);
		if (stx[i]>edx[i])swap(stx[i],edx[i]),swap(sty[i],edy[i]);
		if (flag[i]==1){printf("Orz\n");return 0;}
	}
	scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2); 
	double shit=X1;
	while (shit<=X2){
		shit=shit+(X2-X1)/1000000;
		if (shit==0)continue;
		ans1++;
		k=Y1/shit;
		for (i=1;i<=n+1;i++)
			if (i==n+1||!check(i))break;
		if (i!=n+1)continue;
		double x=Y1/k;
		if (shit*shit+Y1*Y1<=len*len){
			if (shit<0&&atan(k)+pi/2<=ang/360*pi||shit>0&&pi/2-atan(k)<=ang/360*pi)ans++;
		}
	}
	printf("%.4lf\n",(double)ans/ans1);
}
Category: 蒟蒻的滚粗记 | Tags:
12
4
2015
0

UOJ Round #10滚粗记

既然UOJ Easy Round是省选难度,那么请问不带Easy的是什么鬼?

当然我的Blog也出现了点意外,计数器君被drc刷爆了。

T1

诶这是什么神题,我怎么连30分都不会做。

哎呦原来只要可行解呀,这60分是送的呀,出题人送温暖啊。

那就打60分好了。

接着Gold_7AC此题,感到不明觉厉,于是撒了金坷垃打了正解。

如果x柱上的盘的权值在[l,r]之间,那么可以把[l,mid]放在y柱上,[mid+1,r]放在z柱上。

接着再对y、z柱上的盘分治,排序,然后移回来,那么x柱上的盘就完成了排序。

打完之后不停地WA。。。

然后发现数组开小了。。。(打Pascal的Debuff啊)

T2

交互题是什么不明觉厉的东西?

不会,弃坑。

T3

掐指一算,发现暴力拿不了20分。

弃疗了。。。

如果有丧病的OIer对T2或T3感兴趣的话请看链接:http://jiry_2.blog.uoj.ac/blog/1024

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
int n,i,x,ans;
int h[3][1000010];
int f[1000010][2];
using namespace std;
void sol(int l,int r,int p){
	if (l==r)return;
	int mid=l+r>>1;
	int x=(p+1)%3,y=(p+2)%3;
	for (i=h[p][0];i>=h[p][0]-r+l;i--)
		if (h[p][i]<=mid){
			f[++ans][0]=p,f[ans][1]=x;
			h[x][++h[x][0]]=h[p][i];	
		}else{
			f[++ans][0]=p,f[ans][1]=y;
			h[y][++h[y][0]]=h[p][i];
		}
	h[p][0]-=r-l+1;
	sol(l,mid,x);
	sol(mid+1,r,y);
	for (i=h[y][0];i>=h[y][0]-r+mid+1;i--)f[++ans][0]=y,f[ans][1]=x;
	for (i=h[y][0]-r+mid+1;i<=h[y][0];i++){
		f[++ans][0]=x,f[ans][1]=p;
		h[p][++h[p][0]]=h[y][i];
	}
	for (i=h[x][0];i>=h[x][0]-mid+l;i--)f[++ans][0]=x,f[ans][1]=y;
	for (i=h[x][0]-mid+l;i<=h[x][0];i++){
		f[++ans][0]=y,f[ans][1]=p;
		h[p][++h[p][0]]=h[y][i];
	}
	h[x][0]-=mid-l+1;
	h[y][0]-=r-mid;
}
int main(){
	scanf("%d",&n);
	for (i=1;i<=n;i++)scanf("%d",&x),h[0][++h[0][0]]=x;
	for (i=1;i<=n>>1;i++)swap(h[0][i],h[0][n-i+1]);
	sol(1,n,0);
	printf("%d\n",ans);
	for (i=1;i<=ans;i++)printf("%d %d\n",f[i][0]+1,f[i][1]+1);
}
Category: 蒟蒻的滚粗记 | Tags:
12
4
2015
0

BZOJ3261最大异或和

【题目描述】

Description

     

给定一个非负整数序列 {a},初始长度为 N。       
有   M个操作,有以下两种操作类型:
 
1 、A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
2 、Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:
 
a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。  

Input

第一行包含两个整数 N  ,M,含义如问题描述所示。   
第二行包含 N个非负整数,表示初始的序列 A 。 
 
接下来 M行,每行描述一个操作,格式如题面所述。   

Output

假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

Sample Input

5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6

Sample Output

4
5
6

HINT

 

对于      100%  的数据,     0<=a[i]<=10^7  

 

【题解】

首先要知道如何求一个数列的最大区间异或和。

令f[i]=a[1] xor a[2] xor …… xor a[i],那么区间[l,r]的异或值就是f[r] xor f[l-1]。

于是我们把f[i]转化为二进制插入线段树,那么枚举r,可以在trie树上贪心地寻找l。

那么这道题只要把f[i]插入可持久化线段树就可以了。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=300010;
int n,m,sum,i,l,r,x,cnt;
int a[M*10],root[M*10];
struct node{int l,r,w;}tree[M*50];
void addtrie(int &p,int x,int dep){
	tree[++cnt]=tree[p],p=cnt,tree[p].w++;
	if (dep<0)return;
	if (x&(1<<dep))addtrie(tree[p].r,x,dep-1);else addtrie(tree[p].l,x,dep-1);
}
int query(int l,int r,int x){
	int ans=0,p=root[l-1],q=root[r];
	for (int i=25;i>=0;i--)
		if (x&(1<<i)){
			if (tree[tree[q].l].w-tree[tree[p].l].w)p=tree[p].l,q=tree[q].l,ans+=1<<i;
				else p=tree[p].r,q=tree[q].r;	
		}else{
			if (tree[tree[q].r].w-tree[tree[p].r].w)p=tree[p].r,q=tree[q].r,ans+=1<<i;
				else p=tree[p].l,q=tree[q].l;
		}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	n++;
	int sum=0;
	addtrie(root[1],sum,25);
	for (i=2;i<=n;i++){
		scanf("%d",&a[i]);
		sum^=a[i];
		root[i]=root[i-1];
		addtrie(root[i],sum,25);
	}
	for (i=1;i<=m;i++){
		char opt[10];
		scanf("%s",opt);
		if (opt[0]=='A'){
			scanf("%d",&x);
			a[++n]=x;
			sum^=a[n];
			root[n]=root[n-1];
			addtrie(root[n],sum,25);	
		}else{
			scanf("%d%d%d",&l,&r,&x);
			printf("%d\n",query(l,r,sum^x));
		}
	}
}
Category: 蒟蒻的BZOJ刷题记 | Tags:
12
4
2015
0

BZOJ3673/3674可持久化并查集

【题目描述】

Description

Description:
自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就可以轻松虐!
zky:……

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
0<n,m<=2*10^5


 

Input

 

Output

 

Sample Input

5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2

Sample Output

1
0
1

HINT

 

Source

【题解】

其实窝萌可以不用路径压缩,只要按秩合并就可以了。

那么我们需要一个可持久化数组来维护每个集合的大小和关键字。

那么用可持久化线段树来实现就可以了。

然而在交加强版的时候无故RE不多说。。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=210000;
struct Node{int l,r,fa,cnt;}tree[N*50];
int root[N],cnt,n,m;
void update(int l,int r,int &p,int x,int y,int z){
	tree[++cnt]=tree[p];p=cnt;
	if(l==r){tree[p].fa=y;tree[p].cnt=z;return;}
	int mid=l+r>>1;
	if(x<=mid)update(l,mid,tree[p].l,x,y,z);else update(mid+1,r,tree[p].r,x,y,z);
}
int query(int l,int r,int p,int x){
	if(l==r)return p;
	int mid=l+r>>1;
	if(x<=mid)return query(l,mid,tree[p].l,x);else return query(mid+1,r,tree[p].r,x);
}
int search(int p,int x){
	int t=query(1,n,p,x);
	if(tree[t].fa==x)return t;else return search(p,tree[t].fa);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)update(1,n,root[0],i,i,1);
	int ans=0;
	for(int i=1;i<=m;i++){
		int op,x,y;
		scanf("%d",&op);
		root[i]=root[i-1];
		if(op==1){
			scanf("%d%d",&x,&y);
			x^=ans;
			y^=ans;
			int p=search(root[i],x),q=search(root[i],y);
			if(tree[p].fa==tree[q].fa)continue;
			if(tree[p].cnt>tree[q].cnt)swap(p,q);
			update(1,n,root[i],tree[p].fa,tree[q].fa,0);
			update(1,n,root[i],tree[q].fa,tree[q].fa,tree[p].cnt+tree[q].cnt);
		}else
		if(op==2){
			scanf("%d",&x);
			x^=ans;
			root[i]=root[x];
		}else{
			scanf("%d%d",&x,&y);
			x^=ans;
			y^=ans;
			int p=search(root[i],x),q=search(root[i],y);
			printf("%d\n",ans=(tree[p].fa==tree[q].fa));
		}
	}
}
Category: 蒟蒻的BZOJ刷题记 | Tags:
12
3
2015
0

BZOJ贴题计划第一弹

请不要误以为窝转回P了,窝只是来贴一发题。
无标题
无标题
好吧窝来写一下题解。
[Bzoj1601]最小生成树。
[Bzoj1611]Bfs+乱搞。
[Bzoj1595]模拟+双向链表维护。
[Bzoj1596]树的最小覆盖集,贪心或Dp都可以。
[Bzoj1593]线段树。
[Bzoj1594]二分+并查集+乱搞。
[Bzoj1715]Spfa找负权圈。
[Bzoj1735][Bzoj1741]二分图最大匹配。
[Bzoj1717]字符串Hash。
f3cc669b033b5bb5a9e8d06433d3d539b700bc62_副本
 
 
Category: 蒟蒻的口胡 | Tags:
12
2
2015
0

BZOJ3207花神的嘲讽计划Ⅰ

【题目描述】

Description

背景
花神是神,一大癖好就是嘲讽大J,举例如下:
“哎你傻不傻的!【hqz:大笨J】”
“这道题又被J屎过了!!”
“J这程序怎么跑这么快!J要逆袭了!”
……
描述
这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听。以下是部分摘录:
1.
“J你在讲什么!”
“我在讲XXX!”
“哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!”
“……”
2.
“J你XXX讲过了没?”
“……”
“那个都不讲你就讲这个了?哎你傻不傻的!”
“……”
DJ对这种情景表示非常无语,每每出现这种情况,DJ都是非常尴尬的。
经过众蒟蒻研究,DJ在讲课之前会有一个长度为N方案,我们可以把它看作一个数列;
同样,花神在听课之前也会有一个嘲讽方案,有M个,每次会在x到y的这段时间开始嘲讽,为了减少题目难度,每次嘲讽方案的长度是一定的,为K。
花神嘲讽DJ让DJ尴尬需要的条件:
在x~y的时间内DJ没有讲到花神的嘲讽方案,即J的讲课方案中的x~y没有花神的嘲讽方案【这样花神会嘲讽J不会所以不讲】。
经过众蒟蒻努力,在一次讲课之前得到了花神嘲讽的各次方案,DJ得知了这个消息以后欣喜不已,DJ想知道花神的每次嘲讽是否会让DJ尴尬【说不出话来】。
 

Input

第1行3个数N,M,K;
第2行N个数,意义如上;
第3行到第3+M-1行,每行K+2个数,前两个数为x,y,然后K个数,意义如上;

Output

对于每一个嘲讽做出一个回答会尴尬输出‘Yes’,否则输出‘No’

Sample Input

8 5 3
1 2 3 4 5 6 7 8
2 5 2 3 4
1 8 3 2 1
5 7 4 5 6
2 5 1 2 3
1 7 3 4 5

Sample Output

No
Yes
Yes
Yes
No

HINT

题中所有数据不超过2*10^9;保证方案序列的每个数字<=N

2~5中有2 3 4的方案,输出No,表示DJ不会尴尬

1~8中没有3 2 1的方案,输出Yes,表示DJ会尴尬

5~7中没有4 5 6的方案,输出Yes,表示DJ会尴尬

2~5中没有1 2 3的方案,输出Yes,表示DJ会尴尬

1~7中有3 4 5的方案,输出No,表示DJ不会尴尬

Source

【题解】

题意真是冗长不清,其实就是:询问一个区间内有没有某个子串。

那么考虑hash。

把连续k个数字存起来,然后扔进可持久化线段树就可以了。

这里有一个技巧:开一个unsigned long long让其自然溢出,当然由于线段树是实时开结点的所以l和r可以搞得很大。

这里有一个trick:mid=l+r>>1的赋值方法会RE,所以要用更精妙的写法。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 18446744073709551615UL
typedef unsigned long long ull;
using namespace std;
const int M=200010;
int n,m,k,i,x,y,cnt;
int root[M],a[M],b[M];
ull hash[M];
struct node{int l;int r;int w;}tree[M*40];
void update(ull l,ull r,int &p,ull tmp){
	tree[++cnt]=tree[p],p=cnt,tree[p].w++;
	if (l==r)return;
	ull mid=l/2+r/2;
	if ((l&1)&&(r&1))mid++;
	if (tmp<=mid)update(l,mid,tree[p].l,tmp);
		else update(mid+1,r,tree[p].r,tmp);
}
int query(ull l,ull r,int p,ull tmp){
	if (l==r)return tree[p].w;
	ull mid=l/2+r/2;
	if ((l&1)&&(r&1))mid++;
	if (tmp<=mid)return query(l,mid,tree[p].l,tmp);
		else return query(mid+1,r,tree[p].r,tmp);
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for (i=1;i<=n;i++)scanf("%d",&a[i]),hash[i]=hash[i-1]*233+a[i];
	ull tmp=1;for (i=1;i<=k;i++)tmp*=233;
	for (i=k;i<=n;i++)root[i]=root[i-1],update(0,inf,root[i],hash[i]-hash[i-k]*tmp);
	while (m--){
		scanf("%d%d",&x,&y);
		for (i=1;i<=k;i++)scanf("%d",&b[i]);
		ull tmp=0;
		for (i=1;i<=k;i++)tmp=tmp*233+b[i];
		if (query(0,inf,root[y],tmp)-query(0,inf,root[x+k-2],tmp))printf("No\n");
			else printf("Yes\n");
	}
}
Category: 蒟蒻的BZOJ刷题记 | Tags:
12
1
2015
0

Contest20151130滚粗记

听说这是JSOI2015Day2

膜了贵省的题目,感到不明觉厉。

Orz NiroBC 230

Orz Gold_7 220

Orz Chrysanthemum 220

我等蒟蒻第三题炸飞,120收场。

T1

第一眼看到题目慌掉了。让我打个暴力压压惊。

好像答案就是2nk。。。。

T2

第一眼看到题目慌掉了。让我打个暴力压压惊。

诶这个K究竟有什么用,不明觉厉啊。那就20分好了。

正解是:

二分答案(什么居然是分数规划)

那么如果存在更优解,显然有:[tex]\frac{M(i,j)-m(i,j)}{j-i+K}>b[/tex]

首先暴力处理出len=l的情况。

显然对于len(l,r],如果它能产生最优解,那么可以得到:

M(i,j)=a[i],m(i,j)=a[j]或M(i,j)=a[j],m(i,j)=a[i]。

那么将分母乘过去,就有:a[i]+b*i-(a[j]+b*j)>b*K或a[i]-b*i-(a[j]-b*j)>b*K。

令c[i]=a[i]+b*i或a[i]-b*i,那么等式成立的条件是:

存在i,j,满足:l<j-i+1<=r,c[i]-c[j]>b*K。

那么就可以单调队列辣!!!

T3

第一眼看到题目慌掉了,突然发现这道题好像做过类似的。

恩好像跟前面那个Count on a tree差不多,写个可持久化trie树吧。

恩我第一次写。

恩我过样例了。

恩我炸了。

原来是lca的时候大于小于号打错了。

(听说这道题还有一个不明觉厉的hash做法)

Codes

#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int maxn=1000000007;
ll n,k;
ll quickmi(ll x,ll y,ll mod){
	ll ans=1;
	while (y){
		if ((y&1)==1)ans=ans*x%mod;
		x=x*x%mod;
		y=y>>1;
	}
	return ans;
}
int main(){
	freopen("subset.in","r",stdin);
	freopen("subset.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	printf("%lld\n",quickmi(2,n*k,maxn));
}
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int M=100010;
double a[M],c[M];
int cas,n,K,l,r,i;
struct node{int head;int tail;int w[M];}h1,h2;
int check(double b){
	for (int i=1;i<=n;i++)c[i]=a[i]+b*i;
	h1.head=1,h1.tail=1,h1.w[1]=n;
	for (int i=n-l+1;i>=1;i--){
		while (h1.head<h1.tail&&h1.w[h1.head]>i+r-1)h1.head++;
		if (c[i]-c[h1.w[h1.head]]>=b*K)return 1;
		while (h1.head<=h1.tail&&c[h1.w[h1.tail]]>=c[i+l-2])h1.tail--;
		h1.w[++h1.tail]=i+l-2;
	}
	for (int i=1;i<=n;i++)c[i]=-a[i]+b*i;
	h1.head=1,h1.tail=1,h1.w[1]=n;
	for (int i=n-l+1;i>=1;i--){
		while (h1.head<h1.tail&&h1.w[h1.head]>i+r-1)h1.head++;
		if (c[i]-c[h1.w[h1.head]]>=b*K)return 1;
		while (h1.head<=h1.tail&&c[h1.w[h1.tail]]>=c[i+l-2])h1.tail--;
		h1.w[++h1.tail]=i+l-2;
	}
	return 0;
}
int main(){
	scanf("%lld",&cas);
	while (cas--){
		scanf("%d%d%d%d",&n,&K,&l,&r);
		for (i=1;i<=n;i++)scanf("%lf",&a[i]);
		double L=0,R=1000;
		h1.head=1,h1.tail=1,h2.head=1,h2.tail=1;
		h1.w[1]=1,h2.w[1]=1;
		for (i=2;i<=n;i++){
			while (h1.head<h1.tail&&h1.w[h1.head]<i-l+1)h1.head++;
			while (h2.head<h2.tail&&h2.w[h2.head]<i-l+1)h2.head++;
			while (h1.head<=h1.tail&&a[h1.w[h1.tail]]<a[i])h1.tail--;
			while (h2.head<=h2.tail&&a[h2.w[h2.tail]]>a[i])h2.tail--;
			h1.w[++h1.tail]=i;
			h2.w[++h2.tail]=i;
			if (i>=l)L=max(L,(a[h1.w[h1.head]]-a[h2.w[h2.head]])/(l-1+K));
		}
		l++;
		if (l<=r){
			while (R-L>0.000001){
				double mid=(L+R)/2;
				if (check(mid))L=mid;else R=mid;
			}
		}
		printf("%.4lf\n",L);
	}
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=200010;
int n,i,x,y,m,edgenum,cnt;
char a[M];
int head[M],vet[M],next[M],root[M],dep[M];
int fa[M][17];
char ch[M][20];
char st[20];
struct node{int w;int son[26];}tree[M*10];
void addedge(int x,int y){
	vet[++edgenum]=y;
	next[edgenum]=head[x];
	head[x]=edgenum;
}
void addtrie(int &p,int x,int dep){
	tree[++cnt]=tree[p],p=cnt,tree[p].w++;
	if (dep==strlen(ch[x]))return;
	addtrie(tree[p].son[ch[x][dep]-'a'],x,dep+1);
}
int query(int x,int dep){
	if (x==0&&dep)return 0;
	if (dep==strlen(st))return tree[x].w;
	return query(tree[x].son[st[dep]-'a'],dep+1);
}
int lca(int x,int y){
	if (dep[x]<dep[y])swap(x,y);
	int t=dep[x]-dep[y];
	for (int i=0;i<=16;i++)
		if (t&(1<<i))x=fa[x][i];
	for (int i=16;i>=0;i--)
		if (fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	if (x==y)return x;
	return fa[x][0];
}
void dfs(int u,int cnt){
	int e,v;
	if (u!=1)root[u]=root[fa[u][0]],addtrie(root[u],cnt,0);
	for (int i=1;i<=16;i++)
		if ((1<<i)<=dep[u])fa[u][i]=fa[fa[u][i-1]][i-1];
			else break;
	for (e=head[u];e;e=next[e]){
		v=vet[e];
		if (v!=fa[u][0])fa[v][0]=u,dep[v]=dep[u]+1,dfs(v,e+1>>1);
	}
}
int main(){
	scanf("%d",&n);
	for (i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		scanf("%s",ch[i]);
		addedge(x,y);
		addedge(y,x);
	}
	dfs(1,-1);
	scanf("%d",&m);
	for (i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		scanf("%s",st);
		printf("%d\n",query(root[x],0)+query(root[y],0)-2*query(root[lca(x,y)],0));
	}
}

 

Category: 蒟蒻的滚粗记 | Tags:
11
29
2015
0

BZOJ1004【HNOI2008】Cards

【题目描述】

Description

小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).

Input

第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1<p<100)。n=Sr+Sb+Sg。接下来 m 行,每行描述
一种洗牌法,每行有 n 个用空格隔开的整数 X1X2...Xn,恰为 1 到 n 的一个排列,表示使用这种洗牌法,
第 i位变为原来的 Xi位的牌。输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种
洗牌法,都存在一种洗牌法使得能回到原状态。

Output

不同染法除以P的余数

Sample Input

1 1 1 2 7
2 3 1
3 1 2

Sample Output

2

HINT

有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。

100%数据满足 Max{Sr,Sb,Sg}<=20。

【题解】

首先要学一个burnside引理:

http://baike.baidu.com/link?url=spMguL5BAA65FQ2ToT9aeaAPZGmPGW4MP63GrgsFofA3_s9VB0c3yVzaY_fCFDb2Tf4eLpvjir2DUmiBxkvBWq

那么首先求出所有的置换,显然置换的循环在不变元素中是同一个颜色,于是就相当于一个物品。

那么可以考虑一个三维背包,然后再求个逆元。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,p,mod,x,y,z,i,j,ans,xx,yy;
int flag[1010],b[1010];
int a[110][110];
int f[110][110][110];
int dfs(int x,int i){
	flag[i]=1;
	if (!flag[a[x][i]])return dfs(x,a[x][i])+1;
	return 1;
}
int dp(int q){
	int sum=0,i,j,k;
	memset(flag,0,sizeof flag);
	memset(f,0,sizeof f);
	for (i=1;i<=n;i++)
		if (!flag[i])b[++sum]=dfs(q,i);
	f[0][0][0]=1;
	for (int p=1;p<=sum;p++)
		for (i=x;i>=0;i--)
			for (j=y;j>=0;j--)
				for (k=z;k>=0;k--){
					if (i>=b[p])f[i][j][k]=(f[i][j][k]+f[i-b[p]][j][k])%mod;
					if (j>=b[p])f[i][j][k]=(f[i][j][k]+f[i][j-b[p]][k])%mod;
					if (k>=b[p])f[i][j][k]=(f[i][j][k]+f[i][j][k-b[p]])%mod;
				}
	return f[x][y][z];
}
void exgcd(int x,int y){
	if (!y){xx=1;yy=0;return;}
	exgcd(y,x%y);
	int xxx=yy;
	int yyy=xx-x/y*xxx;
	xx=xxx;
	yy=yyy;
}
int main(){
	scanf("%d%d%d%d%d",&x,&y,&z,&m,&mod);
	n=x+y+z;
	for (i=1;i<=m;i++)
		for (j=1;j<=n;j++)scanf("%d",&a[i][j]);
	m++;
	for (i=1;i<=n;i++)a[m][i]=i;
	for (i=1;i<=m;i++)ans=(ans+dp(i))%mod;
	exgcd(m,mod);
	while(xx<=0)xx+=mod;
	printf("%d\n",ans*xx%mod);
}
Category: 蒟蒻的BZOJ刷题记 | Tags:
11
29
2015
0

OrzNiroBC

1:1 起初,NiroBC创造CS。
1:2 Turing机是空虚混沌,一切物理定律都还不适用。
1:3 NiroBC说,要有确定性自动机,就有了确定性自动机。他看确定性自动机是好的,就把计算机结构设定为von Neumann,并让之永远不变,不因参照系的改变而改变。
1:4 NiroBC称范围在1~100,000,000之间的复杂度为“可AC”,称这个区间以外的光为“TLE”。
1:5 有AC的,有TLE的,有CE,有WA,这是头一日。
1:6 NiroBC说,程序之间要有上下,就造出分数来,将程序分开了。
1:7 他把计算机设定为一开始电子管,然后是晶体管,最后是集成电路。NiroBC称它们为三代计算机。这是第二日。
1:8 NiroBC说:天下的算法要聚集在一处,使不可停机算法露出来。他将可停机的算法分类,又让上面的算法相似,以便让人们认为算法是自在的。
1:9 他在可停机算法里面加P、NP、NPC以及很多其他化合物,NiroBC称这种加过杂质的算法为复杂度。NiroBC看着是好的。
1:10 他又造出不同复杂度的算法,将P和NP混合在一起,又造出可递归的枚举集。他看这些算法是好的,就埋在离散数学下和组合优化下,又使之丰富。他还造出量子算法来放置于水底。这是第三日。
1:11 NiroBC又造出OJ。他又造出几种将来会有的毒瘤OJ的原型,和他们应该会用的奇技淫巧埋在一起,以便让他们以为乱搞题是正确的。NiroBC看这是好的。
1:12 NiroBC就将它们埋在地下,但埋得不太深。
1:13 NiroBC说,OJ要发生排名,和难以增加的Rating,并七色的名,各从其类。OJ都公益,除去BZOJ。事就这样成了。NiroBC看这好像太简单了,就将其性能退化,并留下人类选择改良的余地,才看这是好的。这是第四日。
1:14 NiroBC说,天上要有神犇,可以分题目,做论文,定算法,毒瘤,提供膜拜所需的偶像。
1:15 他便造出各种基本数据结构,并让他们能够彼此影响。NiroBC认为这过于简单,世人必不存敬畏,于是又把它分成堆、栈、队列、链表四种数据结构,并让它们无法统一。
1:16 NiroBC又造了高级数据结构,事就这样成了。
1:17 NiroBC看着是好的。于是有算法,有数据结构,这是第五日。
1:18 NiroBC说,算法要多多滋生毒瘤的题目,要有蒟蒻飞在地面以上,天空之中。地要生出活物来,各从其类。Dp的和不需DP的,贪心的和不需贪心的,数据结构优化的和不需数据结构优化的,P的和NP的,以及其他;然后让每个归属于不同的纲,目,科,属,种。
1:19 NiroBC不知道ZYD应该归从在人还是神,于是就把它偷偷藏在ZJ。
1:20 于是世界上生出丰富的题目,Dp的和不需DP的,贪心的和不需贪心的,数据结构优化的和不需数据结构优化的,P的和NP的,以及其他,从Fibonacci堆到主席树。但NiroBC看Fibonacci堆太长了,就让他们不出题,将剩下的思想收集起来,做旧成题目,埋在UOJ里,埋得不太深。
1:21 NiroBC预感到了打表算法,就造出交互式题目。
1:22 NiroBC最后照着自己的样子造了Creation August,照着一本模特杂志造了CLJ;又把他所厌恶的某个敌人的样子丑化后,照着造了段凡丁。
1:23 NiroBC就赐福给他们,又对他们说,要生养众多,遍满地面,治理这地。也要管理海里的算法,空中的神犇,和动物园里各样行动的蒟蒻。
1:24 NiroBC说,看哪,我将遍地上一切结种子的Splay、线段树、一切树上所结有核的LCT、SAM,全赐给你们作食物。
1:25 NiroBC看着一切所造的都甚好。有晚上,有早晨,这是第六日。
1:26 天地万物都造齐了。到第七日,NiroBC造物的工已经完毕,就在第七日歇了他一切的工,休息了。
1:27 NiroBC赐福给第七日,定为圣日,因为在这日NiroBC歇了他一切创造的工,就休假了。NiroBC觉得这样不够好,于是又赐福给第六日,并把它们合称为“圣双休日。”
1:28 创造天地的来历,乃是这样。
517aeb014a90f60321d42bff3c12b31bb151ed1f_副本
 
Category: 蒟蒻的口胡 | Tags:

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com