JLOI2015Day1测试总结

每天都是坑在数据结构题,今天第二题改到交都还是Wa,结果还脑抽的忘记交暴力了。第三题没有看出贪心部分分没来得及写(据说WC原题,但是睡觉去了),第一题的话,Apio讲了类似的题(还好没睡觉),就A了。于是被100分暴虐。。。


T1:

http://www.lydsy.com/JudgeOnline/problem.php?id=4002

这题首先把它补全[(sqrt(d)+b)/2]^n+[(sqrt(d)-b)/2]^n就是个数列通项,用特征方程搞一搞,搞出递推式,然后矩阵乘法求,因为abs((sqrt(d)-b)/2)<1所以上下变化一下就行了,至于乘法会暴long long的话,可以直接开unsigned用快速加。。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
const llu mod=7528443412579576937;
ll b,d,n;
void init(){
	cin>>b>>d>>n;
}
struct Tmx{
	llu a[2][2];
	void clear(){memset(a,0,sizeof(a));}
};
llu mul(llu a,ll b){
	llu res=0;
	while (b){
		if (b&1) res=(res+a)%mod;
		b>>=1; a=(a+a)%mod;
	}
	return res;
}
void mul(Tmx &c,Tmx b){
	Tmx a=c; c.clear();
	for (int i=0;i<2;++i) for (int j=0;j<2;++j)
		for (int k=0;k<2;++k) c.a[i][j]=(c.a[i][j]+mul(a.a[i][k],b.a[k][j]))%mod;
}
Tmx I;
Tmx power(Tmx a,ll t){
	Tmx res=I;
	while (t){
		if (t&1) mul(res,a);
		t>>=1; mul(a,a);
	}
	return res;
}
void work(){
	I.clear(); I.a[0][0]=I.a[1][1]=1;
	Tmx a; a.clear();
	a.a[0][0]=0; a.a[0][1]=(d-b*b)/4;
	a.a[1][0]=1; a.a[1][1]=b;
	a=power(a,n); Tmx x; x.clear();
	x.a[0][0]=2; x.a[0][1]=b;
	mul(x,a); ll ans=x.a[0][0];
	if (!(n&1)) --ans; if (ans<0) ans+=mod;
	cout<<ans<<endl;
}
int main(){
	init(); work();
	fclose(stdin); fclose(stdout);
	return 0;
}

T2:

http://www.lydsy.com/JudgeOnline/problem.php?id=4003

这题我测试的时候想到的是树链剖分,后来发先不用那么麻烦,可以先离线处理,然后dfs一遍(linux就不管暴栈了),进就插入seg,出就删掉,然后查询就行了,在seg中二分,seg维护每个区间要过去的最小初始值就行了但是因为我的nc加我的手抽就挂了

还有一种很显然的做法(太nc了没想到),就是每个点维护一个堆,然后取出最小的如果小于要求就踢掉,然后要变值,于是加标记,然后要合并的父亲,于是可并堆,然后就秒了



第一种

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define PB push_back
using namespace std;
const int maxn=300011;
typedef long long ll;
int n,m,op[maxn]; ll v[maxn],h[maxn];
int pre[maxn],son[maxn],now[maxn],tot=0;
void add(int a,int b){pre[++tot]=now[a]; now[a]=tot; son[tot]=b;}
void init(){
	scanf("%d%d",&n,&m); int f;
	for (int i=1;i<=n;++i) scanf("%lld",h+i);
	for (int i=2;i<=n;++i){
		scanf("%d%d%lld",&f,op+i,v+i);
		add(f,i); 
	}
	op[1]=0; v[1]=0;
}
struct Tseg{
	struct node{
		ll mn,ad,ml; // mn代表可以胜利的最小值 
		ll calc(ll ml,ll ad,ll mn){
			mn-=ad; assert(ml); if (!ml) return 0;
			return ceil(1.0*mn/ml);
		}
		void merge(node a,node b){
			swap(a,b);
			if (log2(a.ml)+log2(b.ml)>=60){
				ml=1LL<<62; ad=0; mn=max(a.mn,calc(a.ml,a.ad,b.mn)); return;
			}
			ml=a.ml*b.ml;
			ad=a.ad*b.ml+b.ad;
			mn=max(a.mn,calc(a.ml,a.ad,b.mn));
		}
	}e[maxn<<2];
	void modify(int p,int l,int r,int w,ll mn,ll ad,ll ml){
//		cerr<<"M "<<l<<' '<<r<<endl;
		if (l==r){
			e[p].mn=mn; e[p].ad=ad; e[p].ml=ml; return;
		}
		int mid=(l+r)>>1;
		if (w<=mid) modify(p<<1,l,mid,w,mn,ad,ml);
		else modify(p<<1|1,mid+1,r,w,mn,ad,ml);
		if (r<=w) e[p].merge(e[p<<1],e[p<<1|1]);
	}
	void Query(int p,int l,int r,int &fir,node &a,int x,ll w){
		if (fir==-1){
			if (l==r){
				if (w>=e[p].mn){a=e[p]; fir=x;} return;
			}
			int mid=(l+r)>>1;
			if (x<=mid) Query(p<<1,l,mid,fir,a,x,w);
			else Query(p<<1|1,mid+1,r,fir,a,x,w);
			if (x>mid){
				if (mid+1!=fir) return;
				node tmp; tmp.merge(e[p<<1],a);
				if (w>=tmp.mn){
					a=tmp; fir=l; return;
				}
				Query(p<<1,l,mid,fir,a,x,w);
			}
		}else{
			if (r+1!=fir) return;
			if (l==r){
				node tmp; tmp.merge(e[p],a);
				if (w>=tmp.mn) {a=tmp; fir=l; return;}
				return;
			}
			int mid=(l+r)>>1;
			node tmp; tmp.merge(e[p<<1|1],a);
			if (w>=tmp.mn){
				a=tmp; fir=(l+r)/2+1;
					Query(p<<1,l,mid,fir,a,x,w);
				return;
			}
			Query(p<<1|1,mid+1,r,fir,a,x,w);
		}
	}
	void modify(int p,ll mn,ll ad,ll ml){
		modify(1,1,n,p,mn,ad,ml);
	}
	int Query(int r,ll w){
		int l=-1; node tmp;
		Query(1,1,n,l,tmp,r,w);
		if (l==-1) l=r+1;
		return l;
	}
}seg;
vector<int> q[maxn];
int ans1[maxn],ans2[maxn],stk[maxn]; ll w[maxn];
void dfs(int x,int dep){
	ll a=0,b=1; if (op[x]==0) a=v[x];else b=v[x];
	seg.modify(dep,h[x],a,b); stk[dep]=x;
	for (int i=0;i<q[x].size();++i){
		int tmp=q[x][i],res=seg.Query(dep,w[tmp]);
		ans1[stk[res-1]]++; ans2[tmp]=dep-res+1;
	}
	for (int p=now[x];p;p=pre[p]) dfs(son[p],dep+1);
}
void work(){
	int s;
	for (int i=1;i<=m;++i) scanf("%lld%d",w+i,&s),q[s].PB(i);
	dfs(1,1);
	for (int i=1;i<=n;++i) printf("%d\n",ans1[i]);
	for (int i=1;i<=m;++i) printf("%d\n",ans2[i]);
}
int main(){
	init();
	work();
	return 0;
}


这么好的时间都不想再交了


第二种


#include<ctime>
#include<cmath>
#include<cstdio>
#include<cassert>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=300011;
template<typename T>
inline void read(T &x){
	bool a=0; char ch; while (!isdigit(ch=getchar())) if (ch=='-') a=1;
	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; if (a) x=-x;
}
ll h[maxn],v[maxn]; int n,m,fa[maxn],op[maxn];
void init(){
	read(n),read(m);
	for (int i=1;i<=n;++i) read(h[i]);
	for (int i=2;i<=n;++i) read(fa[i]),read(op[i]),read(v[i]);
}
struct Tzpt{
	struct node{
		node *l,*r; int dis;
		ll ad,ml,w; int pos;
		void add(ll ad_){if (dis==-1) return; ad+=ad_; w+=ad_;}
		void mul(ll ml_){if (dis==-1) return; ml*=ml_; ad*=ml_; w*=ml_;}
	}e[maxn],*null,*root[maxn];
	int tot;
	void clear(node &x,int p_,ll w_){
		x.l=x.r=null; x.dis=0; x.ad=0; x.ml=1; x.w=w_; x.pos=p_;
	}
	node *newnode(int p_,ll w_){
		clear(e[tot],p_,w_); return &e[tot++];
	}
	void clear(){
		null=e; null->l=null->r=null; null->dis=-1; 
		null->ad=0,null->ml=1; tot=1;
		for (int i=1;i<=n;++i) root[i]=null;
	}
	void pushdown(node *x){
		if (x->ml!=1){
			x->l->mul(x->ml); x->r->mul(x->ml); x->ml=1;
		}
		if (x->ad!=0){
			x->l->add(x->ad); x->r->add(x->ad); x->ad=0;
		}
	}
	node *merge(node *a,node *b){
		if (a==null) return b; if (b==null) return a;
		if (a->w>b->w) swap(a,b);
		pushdown(a); 
		a->r=merge(a->r,b);
		if (a->l->dis<a->r->dis) swap(a->l,a->r);
		a->dis=a->r->dis+1; return a;
	}
	void pop(int x){pushdown(root[x]); root[x]=merge(root[x]->l,root[x]->r);}
	void push(int x,ll w,int pos){root[x]=merge(root[x],newnode(pos,w));}
}zpt;
int ans1[maxn],ans2[maxn],dep[maxn],w[maxn];
void work(){
	dep[1]=1; for (int i=2;i<=n;++i) dep[i]=dep[fa[i]]+1;
	zpt.clear(); ll s;
	for (int i=1;i<=m;++i){
		read(s); read(w[i]); zpt.push(w[i],s,i);
	}
	for (int i=1;i<=m;++i) ans2[i]=dep[w[i]];
	
	for (int i=n;i>=1;--i){
		Tzpt::node *&x=zpt.root[i];
		while (x!=zpt.null && x->w<h[i]){
			int a=x->pos; ans2[a]=dep[w[a]]-dep[i];
			zpt.pop(i); ++ans1[i];
		}
		if (op[i]==0) x->add(v[i]);else x->mul(v[i]);
		if (i!=1) zpt.root[fa[i]]=zpt.merge(zpt.root[fa[i]],x);
	}
	for (int i=1;i<=n;++i) printf("%d\n",ans1[i]);
	for (int i=1;i<=m;++i) printf("%d\n",ans2[i]);
}
int main(){
	init();
	work();
	return 0;
}

堆比线段树快多了,只要3000+ms


T3:

首先这题按权值排序,然后如果已经选了的不能构成就把自己加进去,然后高斯消元来判断,不过这题精度真心蛋疼,对着数据都改了10min。。

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long double ld;
const int maxn=511;
const ld eps=1e-6;
int n,m,a[maxn][maxn],p[maxn],pos[maxn];
void init(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) scanf("%d",&a[i][j]);
	for (int i=1;i<=n;++i) scanf("%d",p+i);
}
inline bool cmp_p(int a,int b){return p[a]<p[b];}
int N=0; ld s[maxn][maxn];
inline int sgn(ld x){if (x<-eps) return -1; return x>eps;}
bool check(int x){
	if (N==m) return false;
	++N;
	for (int i=1;i<=m;++i) s[N][i]=a[x][i];
	for (int i=1;i<N;++i){
		for (int w=1;w<=m;++w)
			if (sgn(s[i][w])){
				ld p=s[N][w]/s[i][w];
				for (int j=w;j<=m;++j) s[N][j]-=p*s[i][j];
				break;
			}
	}
	for (int i=1;i<=m;++i) if (sgn(s[N][i])) return true;
	--N; return false;
}
void work(){
	for (int i=1;i<=n;++i) pos[i]=i; sort(pos+1,pos+n+1,cmp_p);
	int ans=0;
	for (int i=1;i<=n;++i) if (check(pos[i])) ans+=p[pos[i]];
	printf("%d %d\n",N,ans);
}
int main(){
//	freopen("purchase.in","r",stdin); freopen("purchase.out","w",stdout);
	init();
	work();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值