互测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\)