Loading

2022.7.12 模拟赛

2022.7.12 模拟赛

牛半仙的妹子数

题意

给你 \(T\) 组数据,每组数据给你 \(4\) 个数 \(a,b,c,k\),你需要进行 \(k\) 次操作

假定 \(x=a+b\),则每次:

  • \(x\le c\),则 \(c=c-x,x=2\cdot x\)
  • 否则 \(x=x-c,c=2\cdot c\)

求出 \(k\) 次操作后 \(c\) 的值

\(1\le T\le 10^5,1\le a,b,c,k\le10^9\)

思路

容易发现在这两种操作下 \(c+x\) 值恒定

第一种操作 \(c=c-x=c-(c+x)+c=2\cdot c-(c+x)=2\cdot c\bmod x\)

第二种操作 \(c=2\cdot c=2\cdot c \bmod x\)

最后 \(c=c\cdot2^k \bmod (c+x)\)

快速幂求解

code

#include<bits/stdc++.h>
using namespace std;

#define int long long

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int mod;

inline int qpow(int x,int idx){
	if(!idx) return 1;
	int t=qpow(x,idx>>1);
	if(idx&1) return t*t%mod*x%mod;
	return t*t%mod;
}

inline void solve(){
	int a=read(),b=read(),c=read(),k=read();
	mod=a+b+c;
	cout<<qpow(2,k)*c%mod<<endl;
}

signed main(){
	int T=read();
	while(T--){
		solve();
	}
}

\(\cdot\) 人类智慧题,考场上想了一个小时最后写了暴力

(所以我没有智慧)

牛半仙的妹子图

题意

给你一个 \(n\) 个点 \(m\) 条边的无向图以及图中的起始点 \(rt\) ,每条边 \(i\) 有一个权值 \(w_i\),每个点有一个颜色 \(c_i\)

每次你会从 \(rt\) 出发,走向所有能走到的点,若这次最大承受值\(x\),则你经过的所有边的边权必须小于等于 \(x\)

你每次出发获得的价值是你到的所有点总共的不同颜色数

给你 \(q\) 次询问,每次给你两个数 \(l,r\)

你需要求出 \(\sum_{i=l}^r\)\(rt\) 出发最大承受值为 \(i\) 的价值

本题强制在线

\(1\le n,m\le 5\times 10^5,1\le q\le 10^5,1\le w_i,l,r\le10^9,1\le c_i\le600\)

思路

容易有一个想法就是求出到达每一个点的最短路,从而求出遍历到每个颜色的最大承受值最小是多少

这个可以跑一个 \(spfa\)

由于强制在线,\(so\) 不能用莫队 \(QAQ\)

由于 \(c_i\le 600\) ,可以考虑枚举每一个颜色最小的最大承受值,然后统计每个颜色对 \([l,r]\) 有多少贡献

这样的期望时间复杂度是 \(O(k\cdot m+600\cdot q)\),其中 \(k\)\(spfa\) 的常数

code

#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;
const int C=505;
const int inf=1e9+5;

#define pb push_back
#define int long long
#define re register 

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

struct node{
	int a,b;
};

struct pt{
	int c,x;
	inline bool operator < (const pt X) const{
		return x<X.x;
	}
}a[N];


vector <node> G[N];
vector <int> p;

int n,m,rt,op,mod,cnt;
int c[N],d[605];
int dis[N],vis[N];

inline void spfa(){
	for(int i=1;i<=n;++i) dis[i]=inf;
	vis[rt]=1;
	dis[rt]=0;
	queue <int> q;
	q.push(rt);
	while(!q.empty()){
		re int x=q.front();
		q.pop();
		vis[x]=0;
		for(auto y:G[x]){
			if(dis[y.a]>max(dis[x],y.b)){
				dis[y.a]=max(dis[x],y.b);
				if(!vis[y.a]) q.push(y.a),vis[y.a]=1;
			}
		}
	}
	for(int i=1;i<=n;++i){
		a[i].c=c[i],a[i].x=dis[i];
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;++i){
		if(a[i].x!=inf){
			if(!d[a[i].c])
				d[a[i].c]=1,p.push_back(a[i].x);
		}
	}
	sort(p.begin(),p.end());
}

int q;

signed main(){
	n=read(),m=read(),q=read(),rt=read(),op=read();
	if(op==1) mod=read();
	for(int i=1;i<=n;++i) c[i]=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read(),z=read();
		G[x].pb({y,z});
		G[y].pb({x,z});
	}
	spfa();
	int last=0;
	while(q--){
		//cout<<"qwq"<<endl;
		re int l=read(),r=read();
		if(op) l=(l^last)%mod+1;
		if(op) r=(r^last)%mod+1;
		if(l>r) swap(l,r);
		re int ans=0ll;
		for(re int i=0;i<(int)p.size();++i){
			//cout<<p[i]<<endl;
			if(p[i]>r) break;
			ans+=(r-max(p[i],l)+1);
			//cout<<ans<<endl;
		}
		last=ans;
		printf("%lld\n",ans);
	}
}

考试的时候 \(spfa\) 写出来了,但转移的时候还是下意识的写了 \(dis[y.a]=dis[x]+y.b\),实际上应该是 \(dis[y.a]=max(dis[x],y.b)\)

关键是考场上没写对拍,而且在我的玄学改法下过了样例

然后 \(100pts\rightarrow 0pts\),我好恨啊 \(qaq\)

牛半仙的妹子 Tree

题意

给你一个 \(n\) 个点 \(n-1\) 条边的树以及一个数 \(m\)

每个点 \(i\) 有一个点权 \(w_i\),初始均为 \(0\)

接下来有 \(m\) 次操作,每次给你两个数 \(op\)\(x\)

每个操作一秒钟

  • \(op=1\) 则将 \(w_x\) 改为 \(1\),并扩散
  • \(op=2\) 则将所有点点权改为 \(0\)
  • \(op=3\) 则询问这一秒结束 \(w_x\) 是否为 \(1\)

注意,扩散是指:当一个点点权在第 \(i\) 秒被改为 \(1\) 后会在第 \(i+1\) 秒将所有与其相邻的点点权改为 \(1\)

\(1\leq n,m\le 10^5,1\le x\le n,1\le op\le 3\)

思路

考虑若是没有操作 \(2\) 这题可以直接一个 \(bfs\) 解决

因此考虑根据每一个 \(2\) 操作将此问题分成多段

分情况考虑此问题,类似于一个分块的思想

若是第 \(i\)\(2\) 操作到第 \(i+1\)\(2\) 操作之间的操作数 \(k\) 小于等于 \(3000\),则跑 \(O(k^2\log k)\) 的暴力

否则可以跑 \(bfs\),时间复杂度是 \(O(n\cdot\frac mk)\)

这样算下来总的复杂度是 \(O(k^2\log k+n\cdot\frac mk)\) 的,可以跑过此题

这题的 \(k\) 可以依据写的暴力的速度而定,我这个暴力就跑得很快

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;
const int inf=1e9+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,m;
int f[N][20],dep[N];
int d[N];

struct node{
	int x,t;
	inline bool operator < (const node X) const{
		return t<X.t;
	}
};

vector <node> p;
set <node> s;
vector <int> G[N];

inline void bfs(){
	for(int i=1;i<=n;++i) d[i]=inf;
	queue <int> q;
	for(auto x:s){
		if(d[x.x]==inf) d[x.x]=x.t;
		q.push(x.x);
	}
	while(!q.empty()){
		int x=q.front();q.pop();
		for(auto y:G[x]){
			if(d[y]>d[x]+1){
				q.push(y);
				d[y]=d[x]+1;
			}
		}
	}
	for(auto y:p){
		if(y.t>=d[y.x]){puts("wrxcsd");}
		else{puts("orzFsYo");}
	}
}

inline int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=17;i>=0;--i)
		if(dep[f[x][i]]>=dep[y])
			x=f[x][i];
	if(x==y) return x;
	for(int i=17;i>=0;--i)
		if(f[x][i]!=f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}

inline void dfs(int x,int fa){
	f[x][0]=fa;
	dep[x]=dep[fa]+1;
	for(int i=1;i<=17;++i)
		f[x][i]=f[f[x][i-1]][i-1];
	for(auto y:G[x]){
		if(y==fa) continue;
		dfs(y,x);
	}
}

inline void brute_force(){
	for(auto x:p){
		bool flag=0;
		for(auto y:s){
			int a=x.x,b=y.x;
			if(dep[a]+dep[b]-2*dep[lca(a,b)]<=x.t-y.t){
				flag=1;
				puts("wrxcsd");
				break;
			}
		}
		if(!flag) puts("orzFsYo");
	}
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<n;++i){
		int x=read(),y=read();
		G[x].push_back(y);
		G[y].push_back(x);
	}
	int pre=0;
	dfs(1,0);
	for(int T=1;T<=m;++T){
		int op=read(),x=read();
		if(op==1){
			s.insert({x,T});
		}
		if(op==2){
			if(T-pre<=3000) brute_force();
			else bfs();
			pre=T;
			s.clear(),p.clear();
		}
		if(op==3){
			p.push_back({x,T});
		}
		if(T==m&&op!=2){
			if(T-pre<=3000) brute_force();
			else bfs();
		}
	}
}

woc解法好暴力

不过考场上没有想到 \(qwq\)

牛半仙的魔塔(增强版)

这题在图上跑贪心?没有理解

所以不写了

posted @ 2022-07-12 20:21  Into_qwq  阅读(25)  评论(0编辑  收藏  举报