牛客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\%\)
對於另外 \(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\)
-
\(f[i][1]\) 表示前 \(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][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;
}