互測1
T1
暴力的話,直接用高精寫
一共兩種操作,比較大小,加 \(2^x\)
都可以用主席樹優化
比較大小一定是高位到低位第一個不同的位置比較出來的
可以維護雜湊然後線段樹上二分找到第一個不同的位置
加 \(2^x\) 是從第 \(x\) 位往高了一段連續的 \(1\) 變成 \(0\) 然後再把後面一位變成 \(1\)
維護區間內最左邊的零就行
實現上可以建立一顆 \(0\) 樹,區間賦 \(0\) 的時候可以直接改
Code
#include<bits/stdc++.h> #define int long long #define rint signed #define uint unsigned long long #define ls(x) st[x].ls #define rs(x) st[x].rs #define mod 1000000007 #define inf 0x3f3f3f3f3f3f3f3f using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,cnt,S,T,ans; int fa[100010]; int head[100010],ver[400010],to[400010],edge[400010],tot; uint hs[200030]; bool vis[100010]; struct Seg{int mn;uint hs;int ls,rs;}st[200030*40]; int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);} inline void add(int x,int y,int z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;} inline void pushup(int x){ st[x].mn=min(st[ls(x)].mn,st[rs(x)].mn); st[x].hs=st[ls(x)].hs+st[rs(x)].hs; } inline int qpow(int x,int k){ int res=1,base=x; while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;} return res; } void build(int x,int l,int r){ cnt=max(cnt,x);if(l==r) return st[x].mn=l,void(); int mid=(l+r)>>1;st[x].ls=x<<1,st[x].rs=x<<1|1; build(ls(x),l,mid); build(rs(x),mid+1,r); pushup(x); } int query(int x,int l,int r,int L,int R){ if(L<=l&&r<=R) return st[x].mn; int mid=(l+r)>>1,res=200020+1; if(L<=mid) res=min(res,query(ls(x),l,mid,L,R)); if(R>mid) res=min(res,query(rs(x),mid+1,r,L,R)); return res; } void upd(int &x,int l,int r,int L,int R,int pos,bool k){ int pre=x;x=++cnt;st[x]=st[pre]; if(L<=l&&r<=R){if(!k) st[x]=st[pos];else st[x].mn=200020+1,st[x].hs=hs[l];return ;} int mid=(l+r)>>1; if(L<=mid) upd(ls(x),l,mid,L,R,ls(pos),k); if(R>mid) upd(rs(x),mid+1,r,L,R,rs(pos),k); pushup(x); } bool jud(int x,int y,int l,int r){ if(l==r) return st[x].mn==l; int mid=(l+r)>>1; if(st[rs(x)].hs!=st[rs(y)].hs) return jud(rs(x),rs(y),mid+1,r); return jud(ls(x),ls(y),l,mid); } void getans(int x,int l,int r){ if(l==r){if(st[x].mn!=l) (ans+=qpow(2,l-1))%=mod;return ;} int mid=(l+r)>>1; getans(ls(x),l,mid); getans(rs(x),mid+1,r); } struct R{int rt;inline bool operator<(const R &b)const{if(!b.rt) return 1;return jud(rt,b.rt,1,200020);}}dis[100010],t; priority_queue<pair<R,int>,vector<pair<R,int> >,greater<pair<R,int> > >q; signed main(){ #ifdef LOCAL freopen("in","r",stdin); freopen("out","w",stdout); #endif freopen("hellagur.in","r",stdin); freopen("hellagur.out","w",stdout); hs[0]=1;for(int i=1;i<=200020;i++) hs[i]=hs[i-1]*131; n=read();m=read(); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1,x,y,z;i<=m;i++){ x=read(),y=read(),z=read()+1; add(x,y,z),add(y,x,z); fa[getfa(x)]=getfa(y); } build(1,1,200020); S=read(),T=read();if(getfa(S)!=getfa(T)) return puts("-1"),0; dis[S].rt=1;q.push(make_pair(dis[S],S)); while(!q.empty()){ int x=q.top().second;q.pop();if(vis[x]) continue;vis[x]=1; for(int i=head[x];i;i=to[i]){ int y=ver[i],pos;if(vis[y]) continue; pos=query(dis[x].rt,1,200020,edge[i],200020);t=dis[x]; if(pos>edge[i]) upd(t.rt,1,200020,edge[i],pos-1,1,0); upd(t.rt,1,200020,pos,pos,1,1); if(t<dis[y]) dis[y]=t,q.push(make_pair(dis[y],y)); } } getans(dis[T].rt,1,200020); printf("%lld\n",ans); return 0; }
T2
\(\prod\limits_{i=1}^ni!=\prod\limits_{i=1}^ni^{n-i+1}\)
\(n-i+1\) 為偶數的一定都為完全平方數,所以只考慮奇數的值
對每個數分解質因數找出出現奇數次的數,再看最後有沒有剩下的就能判斷能不能都留下
判斷 \(n-1\) 個的情況一定是全留下的情況和某個 \(i!\) 的情況一樣,依次列舉就行
若 \(n\) 為偶數則, \(\prod\limits_{i=1}^ni!=\prod\limits_{i=1}^{\frac{n}{2}}{2i!(2i-1)!}\)
\(\prod\limits_{i=1}^{\frac{n}{2}}2i((2i-1)!)^2\)
\(2^{\frac{n}{2}}(\frac{n}{2})!\)
若 \(n/2\) 為偶數則直接去掉 \(\frac{n}{2}\) 即可 否則要多去掉一個 \(2\)
\(n\) 為奇數則可以去掉 \(n\) 轉化成偶數
於是答案不超過 \(n-3\)
再判斷一下 \(n-2\) 的情況,把每種的雜湊值都塞到一個雜湊表裡,看有相同的有就可以刪兩個
上面的操作都可以給每個質數賦一個隨機的權值然後異或起來,為 \(0\) 則合法
Code
#include<bits/stdc++.h> //#define int long long #define uint unsigned long long #define rint signed #define inf 0x3f3f3f3f3f3f3f3f using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,U,ans; int prime[1000010],g[1000010],cnt; uint val[1000010],sum[1000010],A,B; bool is[1000010]; unordered_map<uint,int>mp; mt19937 rd(time(0)); signed main(){ #ifdef LOCAL freopen("in","r",stdin); freopen("out","w",stdout); #endif freopen("mountain.in","r",stdin); freopen("mountain.out","w",stdout); n=read();srand(time(NULL)); uniform_int_distribution<uint> range(1,~(0llu)); default_random_engine e(rand()); for(int i=2;i<=n;i++){ if(!is[i]) prime[++cnt]=i,g[i]=i,val[i]=range(e); for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ is[i*prime[j]]=1;g[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; } } for(int i=2,x,c,p;i<=n;i++){x=i;while(x!=1){p=g[x];c=0;while(x%p==0) x/=p,c++;if(c&1) sum[i]^=val[p];}} for(int i=1;i<=n;i++) if((n-i+1)&1) A^=sum[i]; if(A==0){printf("%d\n",n);for(int i=1;i<=n;i++) printf("%d ",i);exit(0);} if(!(n&1)){ if(!((n/2)&1)){printf("%d\n",n-1);for(int i=1;i<=n;i++) if(i!=n/2) printf("%d ",i);exit(0);} else{printf("%d\n",n-2);for(int i=1;i<=n;i++) if(i!=n/2&&i!=2) printf("%d ",i);exit(0);} } for(int i=2;i<=n;i++){ A^=sum[i];mp[A]=i; if(A==0){printf("%d\n",n-1);for(int j=1;j<=n;j++) if(i!=j) printf("%d ",j);exit(0);} }A=0; for(int i=2;i<=n;i++){ A^=sum[i]; if(mp.find(A)!=mp.end()){assert(mp[A]!=i);printf("%d\n",n-2);for(int j=1;j<=n;j++) if(i!=j&&j!=mp[A]) printf("%d ",j);exit(0);} } n--;printf("%d\n",n-2);for(int i=1;i<=n;i++) if(i!=2&&i!=n/2) printf("%d ",i); return 0; }
T3
只會垃圾 \(dp\) 設 \(f_{i,j}\) 表示前 \(i\) 個數異或和為 \(j\) 的方案數
加法做完後統一取模就能拿 \(35\)