1. 程式人生 > 其它 >牛客IOI周賽17-普及組

牛客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~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;
}