海亮寄 7.25
前言
业精于勤荒于嬉,行成于思毁于随
正文(模拟赛)
(其实只是一个周赛……)
卦象:昨日夜观星象,参二十八宿,于卯时起卦,呈如意吉祥之兆
感受:感受个头啊,前五个都是水题,T6 感觉是什么神秘的数据结构优化 DP,T7、T8 没看,跑步前进,开摆!
摆烂没啥意思,补补题

剩下的全是一坨啊,要不去写 成都七中 吧(bushi)
突然觉得摆烂好无聊啊,要不去水水知乎或者扒一扒博客?
本来昨天晚上信誓旦旦地说只打 300pts 就摆烂的,结果手痒了
这个环境也不是特别想去写小说。安了安了,树套树模板走起
Upd. 不对啊,T6 这种数据范围变成 \(\log\) 也不像啊,这种东西像组合数啊
T1 & T2 & T3 & T4 & T5
疑似没有提高组 T2 难度
T6
生动形象
点击查看代码
/*
一眼数据结构优化 DP 呐
记 f[i][x][y] 表示用了 i 个点,当前坐标为 (x,y) 的方案数
优化个锤子,转移方程都写不出来
上次和平面上的直线打交道还是平面最近点对(也有可能是扩欧?)
根据以往的经验,直线这种东西是可以平移的
咋做咋做咋做,急急急
还有一个半点,我还想看看 T8 怎么写呢
假设我现在可以枚举直线的起点和终点
所以,答案是什么啊
答案肯定和 gcd 强相关,因此钦定这个东西也是可枚举的
不是 2.5e4 的平方能不能莽过去啊
不对还带个多测和 gcd,我(消音)(消音)(消音)的
vocal,我都忘了直线可以平移啊,所以我直接算 (0,0) 到所有点直接平移不就完了?
时间复杂度能过?
组合数递推复杂度 + 多测 * 枚举终点 * gcd
立个 flag,20min 内把这个题切掉
完犊子,组合数递推式子寄了
woc 怎么寄了
upd. 死因:没删 freopen
*/
#include<bits/stdc++.h>
#define int long long
#define db long double
using namespace std;
const int N=505,MOD=1e9+7;
int n,w,h,d,C[N][N];
inline void ADD(int &x,int y){
x%=MOD;y%=MOD;x=(x+y)%MOD;
return;
}
inline void init(){
C[0][0]=1;
for(int i=1;i<N;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
return;
}
inline db dis(int x,int y){return sqrt((x*x*1.0+y*y*1.0));}
inline int cal(int x,int y){
int g=__gcd(x,y);
int k=(int)(ceil(d/dis(x/g,y/g)));
if(k*(n-1)>g)return 0;
// 剩下的一堆点里面挑 n-2 个
// 不是?我算错了???
// 那很那很了
// 组合数没寄啊……
// 等一下,我可以随便挑吗?
// 哦我(消音)忘了两点中距离限制了
// 可以转化成中间必须隔开多少个点
// 还是随便做,吗?
// 在 n 个点中选取 m 个点并且选的两点之间至少要有 k 个点的方案数 = C[n-(m-1)k][m]?
// 掐头去尾 g-1-(k-1)*2 个点里挑?挑 n-2 个点?要求间隔 k-1 个点?
// 过样例了!
int tot=g-1-(k-1)*2;
int ans=C[tot-(n-3)*(k-1)][n-2];
if(x&&y)ans=ans*2%MOD;
return ans*(w-x+1)%MOD*(h-y+1)%MOD;
}
inline void solve(){
cin>>n>>w>>h>>d;
if(n==1){cout<<(w+1)*(h+1)<<'\n';return;}
int ans=0;
for(int i=0;i<=w;i++)
for(int j=0;j<=h;j++)
if(i!=0||j!=0)ADD(ans,cal(i,j));
cout<<ans<<'\n';
return;
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
init();
// cerr<<C[8][3]<<endl;
int T;cin>>T;while(T--)solve();
return 0;
}
T7
交互抽卡题
T8
赛场上瞪出来了,没想到还有更加好写的启发式合并
子树内维护最大与次大序列是显然的,每个点开个大根堆,叶子向根合并即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define vi vector<int>
#define pb push_back
using namespace std;
const int N=1e5+5;
int n,rt[N];vi G[N];priority_queue<int> q[N];
inline int merge(int x,int y){
if(q[x].size()<q[y].size())swap(x,y);
while(!q[y].empty()){
int u=q[y].top();q[y].pop();
q[x].push(u);
}
return x;
}
inline void dfs(int u,int fa){
for(int v:G[u]){
if(v==fa)continue;
dfs(v,u);rt[u]=merge(rt[u],rt[v]);
}
int res=1;
if(q[rt[u]].size()>=1)res+=q[rt[u]].top(),q[rt[u]].pop();
if(q[rt[u]].size()>=1)res+=q[rt[u]].top(),q[rt[u]].pop();
q[rt[u]].push(res);
return;
}
inline void solve(){
cin>>n;
for(int i=1;i<=n-1;i++){
int u,v;cin>>u>>v;
G[u].pb(v),G[v].pb(u);
}
for(int i=1;i<=n;i++)rt[i]=i;
dfs(1,0);
cout<<q[rt[1]].top()<<'\n';
return;
}
inline void clr(){
for(int i=1;i<=n;i++){
G[i].clear();rt[i]=0;
while(!q[i].empty())q[i].pop();
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;cin>>T;while(T--)solve(),clr();
return 0;
}
小结
走了走了,收拾东西准备跑路!
后记
世界孤立我任它奚落
完结撒花!

浙公网安备 33010602011771号