241119 noip 模拟赛

省流:\(100 + 50 + 45 + 32\)。rk8,喜提前十名中唯一没过t2的。

T1

题意:对于一棵树,记 \(f(i)\) 表示 \(\sum_{1 \leq j \leq n} dis(i,j)\),其中 \(dis(i,j)\) 表示树上 \(i,j\) 之间的距离。

多测,每次给定一个 \(x\),你需要找出最小的一个 \(n\),使得存在一个 \(n\) 个点的树,其上存在两个点 \(u,v\) 使得 \(f(u) - f(v) = x\),输出 \(n\)

\(T \leq 10^5,x \leq 10^{18}\)

对于一颗树,我们选择 \(u\) 为某叶子节点,\(v\) 为树的重心,可以近似找到树的最大能匹配到的 \(x\),考虑 \(f(v)\) 换根到 \(f(u)\) 的过程,发现每次换到一个节点 \(s\) 时,\(f(s) - f(v)\) 会增加 \(2sz_v - n\),发现这个值形如 \(1 + 3 + \cdots + (2 \times p - 1)\)\(2 + 4 + \cdots + 2 \times p\),于是我们可以找出最小的 \(p\) 满足这个值大于等于 \(x\),稍微处理一下奇偶性就行。

代码:

#include<bits/stdc++.h> #define int long long using namespace std; int t; __int128 val(int x) { int tmp=(x+1)/2; if(x&1) return (__int128)tmp*tmp; else return (__int128)tmp*(tmp+1); } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr),cout.tie(nullptr); cin>>t; while(t--) { int x; cin>>x; int l=1,r=1e18,ans; while(l<=r) { int mid=l+r>>1; if(val(mid)>=(__int128)x) ans=mid,r=mid-1; else l=mid+1; } if(!(ans&1)&&(x&1)) cout<<ans+3<<'\n'; else cout<<ans+2<<'\n'; } return 0; }

T2

可以看这篇题解,讲的很好。

代码:

#include<bits/stdc++.h> using namespace std; const int N=55; int n,m,k,a[N][N]; struct node {int x,y,z,c;};vector<node> ve; int main() { ios::sync_with_stdio(false); cin.tie(nullptr),cout.tie(nullptr); cin>>n>>m>>k; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) cin>>a[i][j]; for(int i=m; i>=1; i--) { for(int j=2; j<=m-i+1; j++) for(int k=1; k<=n; k++) ve.push_back((node){k,i,j,a[k][i]}); for(int j=i+1; j<=2*i-1; j++) for(int k=1; k<=n; k++) ve.push_back((node){k,j,m-i+1,a[k][i]}); for(int j=m-i+2; j<=m+k; j++) for(int k=1; k<=n; k++) ve.push_back((node){k,2*i-1,j,a[k][i]}); } for(int i=m+1; i<=m+k; i++) { for(int j=2; j<=2*m-2; j+=4) for(int k=1; k<=n; k++) ve.push_back((node){k,j,i,i-m}); if((2*m-4)%4!=0) for(int k=1; k<=n; k++) ve.push_back((node){k,2*m-2,i,i-m}); for(int j=1; j<=2*m-1; j++) ve.push_back((node){n+1,j,i,i-m}); } cout<<ve.size()<<endl; for(int i=0; i<ve.size(); i++) cout<<ve[i].x<<" "<<ve[i].y<<" "<<ve[i].z<<" "<<ve[i].c<<endl; return 0; }

闲话:noip 模拟 t2 放 *3100 构造素质呢/fn

T3

题意:给定一个长为 \(n\) 的序列 \(a\)\(a\) 中只有 \(0,1,2,-1\),分别表示石头,布,剪刀和不确定,你需要求出所有替换 \(-1\)\(0,1,2\) 的情况中一个最优出拳策略的得分的和。如果你这局赢了,获得 \(1\) 分,平局不获得,输了获得 \(-10^9\) 分。你必须保证相邻两局出的拳不同。

\(n \leq 2000\)

首先可以暴搜每个 \(-1\) 取的值,然后设 \(dp_{i,j}\) 表示第 \(i\) 局出了 \(j\) 的最大得分,转移显然,这样我们就得到了一个 \(\Theta(3^nn)\) 的做法。注意到我们求最优的局数的 dp 中对于每个 \(i\),只有 \(dp_{i,0},dp_{i,1},dp_{i,2}\) 是有用的,所以我们可以把这三个值扔进 dp 里做,设 \(f_{i,x,y,z,o}\) 表示第 \(i\) 局出了 \(o\),三个值分别为 \(x,y,z\) 的方案数,这样时间复杂度是 \(\Theta(n^4)\)。发现这三个值中只有两个是有用的,因为我一定可以找到一种方案使得没有一局输掉,这跟 \(o\) 有关,时间复杂度降为 \(\Theta(n^3)\)。观察 dp 柿子,发现我们只保留 \(x - y\) 的值也能够正常转移计算答案,这样时间复杂度为 \(\Theta(n^2)\)。具体实现中可以在转移中算出最小值的贡献,最后算出差值的贡献。

#include<bits/stdc++.h> #define int long long using namespace std; const int N=2005,p=998244353; int n,a[N],b[N],pw[N],dp[N][N<<1][3],ans=0; int win[3][3]={ {0,-1,1}, {1,0,-1}, {-1,1,0} }; signed main() { ios::sync_with_stdio(false); cin.tie(nullptr),cout.tie(nullptr); cin>>n; for(int i=1; i<=n; i++) cin>>a[i]; pw[n+1]=1; for(int i=n; i>=1; i--) { pw[i]=pw[i+1]; if(a[i]==-1) pw[i]=pw[i]*3%p; } if(a[1]!=-1) dp[1][1+n][a[1]]=1; else dp[1][1+n][0]=dp[1][1+n][1]=dp[1][1+n][2]=1; for(int i=1; i<n; i++) { for(int j=-i; j<=i; j++) { for(int x=0; x<=2; x++) { if(a[i]!=x&&a[i]!=-1) continue; for(int y=0; y<=2; y++) { if(a[i+1]!=y&&a[i+1]!=-1) continue; if(win[x][y]==1) { if(j<0) (ans+=dp[i][j+n][x]*pw[i+2]%p)%=p; if(j>=0) (ans+=dp[i][j+n][x]*pw[i+2]%p*j%p)%=p; (dp[i+1][min(j,0ll)+1+n][y]+=dp[i][j+n][x])%=p; } else if(win[x][y]==0) { if(j>0) (ans+=dp[i][j+n][x]*pw[i+2]%p)%=p; (dp[i+1][1-j+n][y]+=dp[i][j+n][x])%=p; } else { if(j<=0) (ans+=dp[i][j+n][x]*pw[i+2]%p*(-j)%p)%=p; (dp[i+1][max(j,0ll)+1+n][y]+=dp[i][j+n][x])%=p; } } } } } for(int i=-n; i<=n; i++) (ans+=abs(i)*(dp[n][i+n][0]+dp[n][i+n][1]+dp[n][i+n][2])%p)%=p; cout<<ans; return 0; }

T4

还不会。


__EOF__

本文作者System_Error
本文链接https://www.cnblogs.com/System-Error/p/18555600.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   System_Error  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示