1. 程式人生 > 其它 >互測1

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