2025 GJ 的 CSP-S/NOIP 模拟赛49 总结
得分:\(100+100+76+77\)
赛时以为 T3 不可做,把暴力打满了,之后会了正解但没调出
T4 成功 \(O(n \times 树高)\) 骗分
U636246 C49-T1
有点诈骗
直接做过于困难,考虑建图,相同的字符串代表相同的节点,然后 \(s_i \rightarrow t_i\) 连边,那么是内向基环森林,链上的点可以按照拓扑逆序来重命名,\(s_i = t_i\) 的不用重命名,有几个环就多重命名几次
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i = a; i <= b; i++)
#define F_(i,a,b) for(int i = a; i >= b; i--)
#define pii pair<int,int>
#define fr first
#define sc second
#define mem0(a) memset(a,0,sizeof(a))
#define pb push_back
#define lb(x) (x&(-x))
#define lson u<<1
#define rson u<<1|1
typedef long long ll;
typedef unsigned long long ull;
const int N = 2e5+10,M = 1e4+2;
const double eps = 1e-5;
const ll Mod = 1e9+7;
// huangyuze
int n,tot,rd[N],inh[N],vis[N];
map<string,int> mp;
vector<int> go[N];
void topo(){
queue<int> q;
F(i,1,n) if (!rd[i]) q.push(i);
F(i,1,n) inh[i] = 1;
while (q.size()){
int u = q.front(); q.pop();
inh[u] = 0;
for (auto v:go[u]){
rd[v]--;
if (!rd[v]) q.push(v);
}
}
}
void dfs(int u){
vis[u] = 1;
for (auto v:go[u]) if (!vis[v]) dfs(v);
}
int main(){
freopen("files.in","r",stdin);
freopen("files.out","w",stdout);
cin >> n;
int ans = n;
F(i,1,n){
string s,t;
cin >> s >> t;
if (!mp[s]) mp[s] = ++tot;
if (!mp[t]) mp[t] = ++tot;
if (s == t){ans--; continue;}
go[mp[s]].pb(mp[t]);
++rd[mp[t]];
}
topo();
F(i,1,n) if (inh[i] && !vis[i]) ++ans, dfs(i);
cout << ans;
return 0;
}
U636248 C49-T2
观察到 \(n\) 较小,考虑处理出打死 \(i\) 个怪物的最小代价,查询时二分即可
难点在这个处理,贪心难以做到。通过拆贡献,我们发现当选出的怪物集合固定时,打怪物的顺序肯定是按照 \(a_i+b_i\) 从小到大,于是我们先把 \(a_i+b_i\) 从小到大排序,再跑一次 dp,\(f_{i,j}\) 表示前 \(i\) 个怪物中打死 \(j\) 个的最小代价,这样就是对的
#pragma GCC optimize(2,3,"Ofast","inline")
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i = a; i <= b; i++)
#define F_(i,a,b) for(int i = a; i >= b; i--)
#define pii pair<int,int>
#define fr first
#define sc second
#define mem0(a) memset(a,0,sizeof(a))
#define pb push_back
#define lb(x) (x&(-x))
#define lson u<<1
#define rson u<<1|1
typedef long long ll;
typedef unsigned long long ull;
const int N = 3e3+10,M = 3e5+10;
const double eps = 1e-5;
const ll Mod = 1e9+7;
// huangyuze
int n,m;
struct D{ll a,b;} d[N];
ll ad,dp[N][N],res[N];
bool cmp(D x,D y){
return x.a+x.b > y.a+y.b;
}
int main(){
freopen("hunter.in","r",stdin);
freopen("hunter.out","w",stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> ad;
F(i,1,n) cin >> d[i].a;
F(i,1,n) cin >> d[i].b;
sort(d+1,d+n+1,cmp);
F(i,0,n) F(j,0,n) dp[i][j] = 1e18;
dp[0][0] = 0;
F(i,1,n) F(j,0,i){
if (!j) dp[i][j] = 0;
else dp[i][j] = min(dp[i-1][j],dp[i-1][j-1] + (d[i].a+(j-1)*ad)*(d[i].b+(j-1)*ad));
}
F(i,1,n) res[i] = dp[n][i];
F(i,1,m){
ll x; cin >> x;
int pos = lower_bound(res+1,res+n+1,x)-res-1;
cout << pos << " ";
}
return 0;
}
/*
a_1 b_1 + 0 d b_1 + 0 d a_1 + 0 d d
a_2 b_2 + 1 d b_2 + 1 d a_2 + 1 d d
a_3 b_3 + 2 d b_3 + 2 d a_3 + 4 d d
100 1
1 101
*/
U636250 C49-T3
从部分分到正解
注意到帽子交换后会重新编号,这是个很好的性质
考虑 \(O(nm+q)\) 怎么做,我们考虑预处理出 \(pos_{i,j}\) 表示球在第 \(i\) 个帽子经过前 \(j\) 轮到那个帽子,那么查询 \([l,r]\) 的交换操作时,我们的位置 \(x\) 一定可以通过从 \(1\) 开始某个位置的交换操作到达,设 \(whe_{i,j}\) 表示在前 \(j\) 轮操作后,球在那个位置能使球到 \(i\)。那么答案为 \(pos_{whe_{l-1,x},r}\)
模拟交换过程,一开始设 \(x_i = i\),然后每轮交换 \({x_{a_i},x_{b_i}}\)。观察到 \(j\) 轮后的 \(x_i\) 就是 \(whe_{i,j}\),而且 \(pos_{i,j}\) 与 \(whe_{i,j}\) 对应,于是用可持久化线段树维护
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i = a; i <= b; i++)
#define F_(i,a,b) for(int i = a; i >= b; i--)
#define pii pair<int,int>
#define fr first
#define sc second
#define mem0(a) memset(a,0,sizeof(a))
#define pb push_back
#define lb(x) (x&(-x))
#define lson u<<1
#define rson u<<1|1
typedef long long ll;
typedef unsigned long long ull;
const int N = 2e5+10,M = 1e4+2;
const double eps = 1e-5;
const ll Mod = 1e9+7;
// huangyuze
int n,m,q;
struct CZ{int a,b;} cz[N];
struct SGT{
int rt[N],cnt;
int val[N<<6],ls[N<<6],rs[N<<6];
void build(int &u,int l,int r){
u = ++cnt;
if (l == r){
val[u] = l;
return ;
}
int mid = (l+r)>>1;
build(ls[u],l,mid);
build(rs[u],mid+1,r);
}
void update(int &u,int pre,int l,int r,int p,int d){
u = ++cnt;
if (l == r){
val[u] = d;
} else {
ls[u] = ls[pre], rs[u] = rs[pre];
int mid = (l+r)>>1;
if (p <= mid) update(ls[u],ls[pre],l,mid,p,d);
else update(rs[u],rs[pre],mid+1,r,p,d);
}
}
int query(int u,int l,int r,int p){
if (l == r){
return val[u];
}
int mid = (l+r)>>1;
if (p <= mid) return query(ls[u],l,mid,p);
else return query(rs[u],mid+1,r,p);
}
} pos,whe;
int main(){
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> q;
F(i,1,m) cin >> cz[i].a >> cz[i].b;
pos.build(pos.rt[0],1,n); whe.build(whe.rt[0],1,n);
F(i,1,m){
int px = pos.query(pos.rt[i-1],1,n,cz[i].a), py = pos.query(pos.rt[i-1],1,n,cz[i].b);
int wx = whe.query(whe.rt[i-1],1,n,px), wy = whe.query(whe.rt[i-1],1,n,py);
pos.update(pos.rt[i],pos.rt[i-1],1,n,cz[i].a,py); pos.update(pos.rt[i],pos.rt[i],1,n,cz[i].b,px);
whe.update(whe.rt[i],whe.rt[i-1],1,n,px,wy); whe.update(whe.rt[i],whe.rt[i],1,n,py,wx);
}
F(i,1,q){
int x,l,r;
cin >> x >> l >> r;
cout << whe.query(whe.rt[r],1,n,pos.query(pos.rt[l-1],1,n,x)) << "\n";
}
return 0;
}
/*
5 5 2
2 4
1 4
1 5
3 4
1 2
2 1 3
1 2 4
1 2 3 4 5
1 2 3 4 5
1 4 3 2 5
1 4 3 2 5
2 4 3 1 5
4 1 3 2 5
5 4 3 1 2
4 5 3 2 1
*/

浙公网安备 33010602011771号