每天都是坑在数据结构题,今天第二题改到交都还是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;
}