海亮寄 7.25

前言

业精于勤荒于嬉,行成于思毁于随

正文(模拟赛)

(其实只是一个周赛……)

卦象:昨日夜观星象,参二十八宿,于卯时起卦,呈如意吉祥之兆

感受:感受个头啊,前五个都是水题,T6 感觉是什么神秘的数据结构优化 DP,T7、T8 没看,跑步前进,开摆!

摆烂没啥意思,补补题

image

剩下的全是一坨啊,要不去写 成都七中 吧(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;
}

小结

走了走了,收拾东西准备跑路!

后记

世界孤立我任它奚落

完结撒花!

posted @ 2025-07-25 14:44  sunxuhetai  阅读(10)  评论(0)    收藏  举报