l d x ldx ldx 爆零过程在这里~
数数题
考虑到一个性质是对于每个数,最多存在一个 ≤ 15 \le15 ≤15 的质因子,这样可以将所有数按照其 ≥ 15 \ge15 ≥15 的质因子分组,设 f i , a 1 , a 2 , a 3 , a 4 , a 5 , a 6 f_{i,a_1,a_2,a_3,a_4,a_5,a_6} fi,a1,a2,a3,a4,a5,a6 表示前 i i i 组,它们的 l c m lcm lcm 的 2 , 3 , 5 , 7 , 11 , 13 2,3,5,7,11,13 2,3,5,7,11,13 的幂次分别为 a 1 , a 2 , a 3 , a 4 , a 5 , a 6 a_1,a_2,a_3,a_4,a_5,a_6 a1,a2,a3,a4,a5,a6 的所有 l c m lcm lcm 和,然后枚举第 i + 1 i+1 i+1 组中的每个数转移,注意可以前缀和优化
CODE:
#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define rsz resize
#define sz(x) (int)(x).size()
#define lb lower_bound
#define rb upper_bound
#define all(x) (x).begin(),(x).end()
using namespace std;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):0;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=2005;
int n,a[N];
int pri[41]={17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,1};
int f[8][5][4][3][3][3],g[8][5][4][3][3][3],ss[8][5][4][3][3][3];
vector<int>vl[41];
int main(){
n=read();
for(ri i=1;i<=n;++i)a[i]=read();
for(ri ff=0,i=1;i<=n;++i,ff=0)for(ri j=0;j<41;++j)
if(a[i]==a[i]/pri[j]*pri[j]){a[i]/=pri[j],vl[j].pb(a[i]);break;}
f[0][0][0][0][0][0]=1;
int res=0;
for(ri mt,t,b1,b2,b3,b4,b5,b6,vlx,i=40;~i;--i){
if(!vl[i].size())continue;
memset(ss,0,sizeof(ss));
for(ri j=0,up=vl[i].size();j<up;++j){
memset(g,0,sizeof(g));
mt=1,b1=b2=b3=b4=b5=b6=0;
t=vl[i][j];
while(t%2==0)t/=2,++b1;
while(t%3==0)t/=3,++b2;
while(t%5==0)t/=5,++b3;
while(t%7==0)t/=7,++b4;
while(t%11==0)t/=11,++b5;
while(t%13==0)t/=13,++b6;
for(ri s=1;s<=b1;++s)mt*=2;
for(ri a1=0;a1<8;++a1){
for(ri s=1;s<=b2;++s)mt*=3;
for(ri a2=0;a2<5;++a2){
for(ri s=1;s<=b3;++s)mt*=5;
for(ri a3=0;a3<4;++a3){
for(ri s=1;s<=b4;++s)mt*=7;
for(ri a4=0;a4<3;++a4){
for(ri s=1;s<=b5;++s)mt*=11;
for(ri a5=0;a5<3;++a5){
for(ri s=1;s<=b6;++s)mt*=13;
for(ri a6=0;a6<3;++a6){
Add(g[max(a1,b1)][max(a2,b2)][max(a3,b3)][max(a4,b4)][max(a5,b5)][max(a6,b6)],mul(f[a1][a2][a3][a4][a5][a6],mul(mt,pri[i])));
Add(g[max(a1,b1)][max(a2,b2)][max(a3,b3)][max(a4,b4)][max(a5,b5)][max(a6,b6)],mul(ss[a1][a2][a3][a4][a5][a6],mt));
if(a6<b6)mt/=13;
}
if(a5<b5)mt/=11;
}
if(a4<b4)mt/=7;
}
if(a3<b3)mt/=5;
}
if(a2<b2)mt/=3;
}
if(a1<b1)mt/=2;
}
for(ri a1=0;a1<8;++a1)for(ri a2=0;a2<5;++a2)for(ri a3=0;a3<4;++a3)
for(ri a4=0;a4<3;++a4)for(ri a5=0;a5<3;++a5)for(ri a6=0;a6<3;++a6)
Add(ss[a1][a2][a3][a4][a5][a6],g[a1][a2][a3][a4][a5][a6]);
}
for(ri a1=0;a1<8;++a1)for(ri a2=0;a2<5;++a2)for(ri a3=0;a3<4;++a3)
for(ri a4=0;a4<3;++a4)for(ri a5=0;a5<3;++a5)for(ri a6=0;a6<3;++a6)
Add(res,ss[a1][a2][a3][a4][a5][a6]),Add(f[a1][a2][a3][a4][a5][a6],ss[a1][a2][a3][a4][a5][a6]);
}
cout<<res;
return 0;
}
线性基入门题,对于每个点,把其权值看做属性 A A A ,把连向它的边的边权异或和看做属性 B B B ,然后对属性 B B B 做以属性 A A A 为第一关键字的线性基即可
CODE:
#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define rsz resize
#define sz(x) (int)(x).size()
#define lb lower_bound
#define rb upper_bound
#define all(x) (x).begin(),(x).end()
using namespace std;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
typedef pair<ll,ll> pll;
inline ll readl(){
ll ans=0;
bool f=1;
char ch=gc();
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return f?ans:-ans;
}
const ll inf=1e18;
const int N=1e5+5;
int n,m;
ll a[N],Vl[N],bas[N],all=0;
pll vl[N];
int main(){
n=read(),m=read();
ll w;
for(ri i=1;i<=n;++i)Vl[i]=readl(),all+=Vl[i];
for(ri u,v,i=1;i<=m;++i){
u=read(),v=read(),w=readl();
a[u]^=w,a[v]^=w;
}
for(ri i=1;i<=n;++i)vl[i]=pll(Vl[i],a[i]);
sort(vl+1,vl+n+1);
ll ans=0;
for(ri i=n;i;--i){
for(ri j=62;~j;--j){
if(vl[i].se>>j&1){
if(!bas[j]){ans+=vl[i].fi,bas[j]=vl[i].se;break;}
else vl[i].se^=bas[j];
}
if(!vl[i].se)break;
}
}
cout<<ans*2-all;
return 0;
}
考虑转化题意,按照如下的方式构建思维模型:
现在平面上有 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi) ,保证对于任意时刻满足 x i > 0 , y i > 0 , ∀ i ≠ j , x i ≠ x j & & y i ≠ y j x_i>0,y_i>0,\forall i\not=j,x_i\not=x_j\&\&y_i\not=y_j xi>0,yi>0,∀i=j,xi=xj&&yi=yj ,且每过一个时刻每个点向右平移一个单位,要求支持删掉一个点 i : ( x i y i ≤ 10 ) i:(x_iy_i\le10) i:(xiyi≤10) 或者插入一个点 i : ( x i ≤ 10 , y i ) i:(x_i\le10,y_i) i:(xi≤10,yi) ,询问每次操作结束后的二维偏序最长链
这样的话做法就很显然了:
对于 x , y x,y x,y 这两维分别维护一个下标递增的序列 f f f , f i f_i fi 表示以 x / y x/y x/y 坐标为 i i i 的点作为起点的二维偏序最长链长度,然后每次插入或删除一个点的时候为了保证两维都递增,考虑先消除 x / y x/y x/y 坐标小于它的点,然后插入/删除,这个时候由于在 f f f 序列中的点满足两维偏序关系,因此可以直接取一个后缀 m a x max max 得到新的答案
至于某一维有哪些点比它小可以对 x , y x,y x,y 两维分别用一个 s e t set set 来维护
复杂度 O ( n log n ) O(n\log n) O(nlogn) 乘上一个10的中等常数
CODE:
#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef vector<int> poly;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef pair<int,int> pii;
const int N=1e5+15;
int n,m;
struct sgt{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
int mx[N<<2];
inline void pushup(int p){mx[p]=max(mx[lc],mx[rc]);}
inline void update(int p,int l,int r,int k,int v){
if(l==r){mx[p]=v;return;}
k<=mid?update(lc,l,mid,k,v):update(rc,mid+1,r,k,v);
pushup(p);
}
inline int query(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return mx[p];
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
return max(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
}
#undef lc
#undef rc
#undef mid
}t1,t2;
typedef set<pii>::iterator It;
struct cp1{inline bool operator()(pii a,pii b){return a.fi<b.fi;}};
struct cp2{inline bool operator()(pii a,pii b){return a.se<b.se;}};
set<pii,cp1>S1;
set<pii,cp2>S2;
int lm1,lm2;
inline void insert(int ps,int vl){
vector<pii>t;
S1.insert(pii(ps,vl));
It it=S2.insert(pii(ps,vl)).fi;
while(1){
t.pb(*it);
t1.update(1,1,lm1,it->fi,0);
if(it==S2.begin())break;
--it;
}
for(ri upd,i=0;i<t.size();++i){
upd=t1.query(1,1,lm1,t[i].fi,lm1)+1;
t1.update(1,1,lm1,t[i].fi,upd);
t2.update(1,1,lm2,t[i].se,upd);
}
cout<<t1.mx[1]<<'\n';
}
inline void delet(int ps){
vector<pii>t;
It it=S1.begin();
while(--ps)t2.update(1,1,lm2,it->se,0),t.pb(*it),++it;
t1.update(1,1,lm1,it->fi,0);
t2.update(1,1,lm2,it->se,0);
S1.erase(*it),S2.erase(*it);
for(ri upd,i=t.size()-1;~i;--i){
upd=t2.query(1,1,lm2,t[i].se,lm2)+1;
t1.update(1,1,lm1,t[i].fi,upd);
t2.update(1,1,lm2,t[i].se,upd);
}
cout<<t2.mx[1]<<'\n';
}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
n=read(),m=read();
lm1=n,lm2=m+10;
for(ri op,x,y;m;--m){
op=read();
if(op==1){
x=read(),y=read()+m;
insert(x,y);
}
else delet(read());
}
return 0;
}