牛客IOI周赛17-普及组

比赛链接

牛客IOI周赛17-普及组

C.不平衡数组

题目描述

给定一个长度为 n 的数组。要求相临的数大小不相同,假如相临数的相同,
你可以通过将 a[i]+1 来改变它的大小,但是需要付出 b[i] 的代价,同时对于每
a[i] 只能加一次。问你付出的最小代价。

输入描述:

11 个整数 n,表示数组长度为 n
接下来 n 行,每行 2 个正整数 a[i]b[i],表示 a 数组中的第 i 个数,以及将第 i 个数 +1 的代价。
对于 20% 的数据,保证 b[i]=1
对于另外 10% 的数据,保证所有 a[i] 相等
对于另外 10% 的数据,保证所有的 a[i] 不相等
对于 100% 的数据,1<=n<=2e50<=a[i]b[i]<=1e9

输出描述:

1 行,一个数字 ans,表示最小代价。

示例1

输入

4 1 2 2 2 2 3 4 1

输出

2

解题思路

dp

  • 状态表示:
    • f[i][0] 表示前 i 个数且第 i 个数不加一的最小代价
    • f[i][1] 表示前 i 个数且第 i 个数加一的最小代价
  • 状态计算:
    • a[i1]==a[i] 时,
      • f[i][0]=f[i1][1]
      • f[i][1]=f[i1][0]+a[i].se
    • a[i1]+1==a[i] 时,
      • f[i][0]=f[i1][0]
      • f[i][1]=min(f[i1][0],f[i1][1])+b[i]
    • a[i1]==a[i+1]+1 时,
      • f[i][0]=min(f[i1][0],f[i1][1])
      • f[i][1]=f[i1][1]+b[i]
    • 其他情况,
      • f[i][0]=min(f[i1][0],f[i1][1])
      • f[i][1]=min(f[i1][0],f[i1][1])+b[i]

注意:只要存在一种状态能够转移到当前状态则该状态就应该被计算在内

  • 时间复杂度:O(n)

代码

// Problem: 不平衡数组 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/33347/C // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=2e5+5; int n; LL f[N][2]; PII a[N]; int main() { cin>>n; for(int i=1;i<=n;i++)cin>>a[i].fi>>a[i].se; a[0].fi=-2; for(int i=1;i<=n;i++) { if(a[i-1].fi==a[i].fi) { f[i][0]=f[i-1][1]; f[i][1]=f[i-1][0]+a[i].se; } else if(a[i-1].fi+1==a[i].fi) { f[i][0]=f[i-1][0]; f[i][1]=min(f[i-1][0],f[i-1][1])+a[i].se; } else if(a[i-1].fi==a[i].fi+1) { f[i][0]=min(f[i-1][0],f[i-1][1]); f[i][1]=f[i-1][1]+a[i].se; } else { f[i][0]=min(f[i-1][0],f[i-1][1]); f[i][1]=f[i][0]+a[i].se; } } cout<<min(f[n][0],f[n][1]); return 0; }

D.数列统计

题目描述

求以x结尾的长度为l的不下降正整数数列一共有多少个。对911451407取模

输入描述:

本题有多组数据。
第一行一个正整数T,表示数据组数。

对于每组数据:两个用空格隔开的整数l,x

输出描述:

T行,每行一个答案。

示例1

输入

2 2 1 2 3

输出

1 3

备注:

对于前 10% 的数据, T=10;l,x10
对于前 20% 的数据, T=10;l,x1000
对于前 40% 的数据, T=10;l,x105
对于 100% 的数据, T105;0<l,x106

解题思路

组合数

f[i][j] 表示长度为 i 结尾为 j 的不下降正整数数列方案数,固定最后一个数,有 f[i][j]=k=1jf[i1][k],即 f[i][j]=f[i1][j]+k=1j1f[i1][k]=f[i1][j]+f[i][j1],求解 f[i][j]=f[i1][j]+f[i][j1] 问题等价于从 (1,1) 走,只能向下或向右,问走到 (i,j) 的方案数的经典问题,由于向下要走 i1 次,向右要走 j1 次,即在总的步数 i+j2 中选出 i1 步用来向下走,即 Ci+j2i1

1n 的逆元可以线性递推,求阶乘逆元与求阶乘同理,则:

  • 时间复杂度:O(2e6+T)

代码

// Problem: 数列统计 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/33347/D // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=2e6+5,mod=911451407; int fact[N],inv_fact[N],inv[N]; void init() { fact[0]=fact[1]=inv_fact[0]=inv_fact[1]=inv[1]=1; for(int i=2;i<N;i++) { fact[i]=1ll*fact[i-1]*i%mod; inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; inv_fact[i]=1ll*inv_fact[i-1]*inv[i]%mod; } } int C(int a,int b) { return 1ll*fact[a]*inv_fact[a-b]%mod*inv_fact[b]%mod; } int main() { init(); int t; for(cin>>t;t;t--) { int l,x; cin>>l>>x; cout<<C(l+x-2,x-1)<<'\n'; } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16175353.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示