2022.7.12 模拟赛
2022.7.12 模拟赛
比赛 link
牛半仙的妹子数
题意:
给你 \(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\)
牛半仙的魔塔(增强版)
这题在图上跑贪心?没有理解
所以不写了