牛客IOI周赛17-普及组

比赛链接

牛客IOI周赛17-普及组

C.不平衡数组

题目描述

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

输入描述:

\(1\)\(1\) 个整数 \(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<=2e5,0<=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[i-1]==a[i]\) 时,
      • \(f[i][0]=f[i-1][1]\)
      • \(f[i][1]=f[i-1][0]+a[i].se\)
    • \(a[i-1]+1==a[i]\) 时,
      • \(f[i][0]=f[i-1][0]\)
      • \(f[i][1]=min(f[i-1][0],f[i-1][1])+b[i]\)
    • \(a[i-1]==a[i+1]+1\) 时,
      • \(f[i][0]=min(f[i-1][0],f[i-1][1])\)
      • \(f[i][1]=f[i-1][1]+b[i]\)
    • 其他情况,
      • \(f[i][0]=min(f[i-1][0],f[i-1][1])\)
      • \(f[i][1]=min(f[i-1][0],f[i-1][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\)取模

输入描述:

\(\textbf{本题有多组数据。}\)
第一行一个正整数\(T\),表示数据组数。

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

输出描述:

\(T\)行,每行一个答案。

示例1

输入

2
2 1
2 3

输出

1
3

备注:

对于前 \(10 \%\) 的数据, \(T=10 ; l, x \leq 10\)
对于前 \(20 \%\) 的数据, \(T=10 ; l, x \leq 1000\)
对于前 \(40 \%\) 的数据, \(T=10 ; l, x \leq 10^{5}\)
对于 \(100 \%\) 的数据, \(T \leq 10^{5} ; 0<l, x \leq 10^{6}\)

解题思路

组合数

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

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

  • 时间复杂度:\(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;
}
posted @ 2022-04-21 17:52  zyy2001  阅读(27)  评论(0编辑  收藏  举报