A.夹娃娃
题意:
给
定
n
个
值
a
i
给定n个值a_i
给定n个值ai
q
次
询
问
,
每
次
给
出
l
和
r
q次询问,每次给出l和r
q次询问,每次给出l和r
求
出
区
间
l
到
r
的
和
求出区间l到r的和
求出区间l到r的和
题解:
n
<
=
1
e
5
,
k
<
=
1
e
6
n<=1e5,k<=1e6
n<=1e5,k<=1e6
很
明
显
暴
力
是
不
行
的
很明显暴力是不行的
很明显暴力是不行的
但
是
这
个
方
法
还
是
很
多
的
但是这个方法还是很多的
但是这个方法还是很多的
最
简
单
的
就
是
直
接
前
缀
和
最简单的就是直接前缀和
最简单的就是直接前缀和
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
就
是
区
间
的
和
sum[r]-sum[l-1]就是区间的和
sum[r]−sum[l−1]就是区间的和
除
此
之
外
树
状
数
组
,
线
段
树
都
是
可
以
的
,
但
是
需
要
l
o
g
的
复
杂
度
除此之外树状数组,线段树都是可以的,但是需要log的复杂度
除此之外树状数组,线段树都是可以的,但是需要log的复杂度
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
int a[maxn],sum[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i];
while(k--){
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}
B.莫的难题
题意:
问
用
1
,
2
,
3
,
5
,
9
组
成
的
数
里
问用1,2,3,5,9组成的数里
问用1,2,3,5,9组成的数里
第
C
n
m
m
o
d
1
e
9
+
7
小
的
是
哪
个
第C_n^mmod~1e9+7小的是哪个
第Cnmmod 1e9+7小的是哪个
题解:
首
先
肯
定
要
把
这
个
组
合
数
求
出
来
首先肯定要把这个组合数求出来
首先肯定要把这个组合数求出来
正
常
的
阶
乘
逆
元
操
作
先
求
出
数
组
,
看
是
第
几
位
数
正常的阶乘逆元操作先求出数组,看是第几位数
正常的阶乘逆元操作先求出数组,看是第几位数
然
后
由
于
数
的
每
一
位
是
这
五
位
数
组
成
然后由于数的每一位是这五位数组成
然后由于数的每一位是这五位数组成
这
完
全
可
以
当
成
一
个
五
进
制
数
这完全可以当成一个五进制数
这完全可以当成一个五进制数
1
,
2
,
3
,
5
,
9
对
应
的
分
别
是
0
,
1
,
2
,
3
,
4
1,2,3,5,9对应的分别是0,1,2,3,4
1,2,3,5,9对应的分别是0,1,2,3,4
这
样
就
成
了
一
个
找
五
进
制
数
的
过
程
这样就成了一个找五进制数的过程
这样就成了一个找五进制数的过程
但
是
会
发
现
,
直
接
这
样
找
出
来
的
答
案
并
不
是
我
们
想
要
的
但是会发现,直接这样找出来的答案并不是我们想要的
但是会发现,直接这样找出来的答案并不是我们想要的
因
为
这
个
标
记
第
几
小
的
数
是
一
个
十
进
制
,
他
是
从
0
开
始
的
因为这个标记第几小的数是一个十进制,他是从0开始的
因为这个标记第几小的数是一个十进制,他是从0开始的
但
是
对
于
这
个
数
组
来
说
,
第
1
小
的
数
是
1
但是对于这个数组来说,第1小的数是1
但是对于这个数组来说,第1小的数是1
然
而
你
想
取
到
1
,
应
该
是
一
个
第
0
小
的
数
才
对
应
的
是
1
然而你想取到1,应该是一个第0小的数才对应的是1
然而你想取到1,应该是一个第0小的数才对应的是1
总
的
来
说
意
思
就
是
,
对
于
正
常
的
五
进
制
,
你
想
取
到
的
第
1
小
的
数
是
0
总的来说意思就是,对于正常的五进制,你想取到的第1小的数是0
总的来说意思就是,对于正常的五进制,你想取到的第1小的数是0
所
以
由
于
这
一
个
,
导
致
每
一
位
都
出
现
了
一
个
数
的
偏
差
所以由于这一个,导致每一位都出现了一个数的偏差
所以由于这一个,导致每一位都出现了一个数的偏差
所
以
要
把
每
一
位
的
这
个
数
减
去
,
最
后
化
成
五
进
制
得
到
答
案
所以要把每一位的这个数减去,最后化成五进制得到答案
所以要把每一位的这个数减去,最后化成五进制得到答案
由
于
得
到
的
是
倒
序
的
答
案
,
用
栈
存
输
出
即
可
由于得到的是倒序的答案,用栈存输出即可
由于得到的是倒序的答案,用栈存输出即可
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
ll fact[maxn],inv1[maxn];
ll Pow(ll a, ll b){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
//逆元
ll inv(ll b){
return Pow(b,mod-2)%mod;
}
ll C(ll n,ll m){
if(m>n||n<0||m<0)return 0;
if(m==0||m==n) return 1;
ll res=(fact[n]*inv1[m]%mod*inv1[n-m])%mod;
return res;
}
void init() {
fact[0] = 1;
for (int i = 1; i < maxn; i++) {
fact[i] = fact[i - 1] * i %mod;
}
inv1[maxn - 1] = Pow(fact[maxn - 1], mod - 2);
for (int i = maxn - 2; i >= 0; i--) {
inv1[i] = inv1[i + 1] * (i + 1) %mod;
}
}
int a[]={1,2,3,5,9};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int _;
cin>>_;
init();
while(_--){
ll n,m;
cin>>n>>m;
ll x=C(n,m);
stack<int> s;
while(x>0){
x--;
s.push(x%5);
x/=5;
}
while(s.size())cout<<a[s.top()],s.pop();
cout<<endl;
}
return 0;
}
C. 不平衡数组
题意:
给
2
个
长
度
为
n
的
数
组
a
i
,
b
i
给2个长度为n的数组a_i,b_i
给2个长度为n的数组ai,bi
你
可
以
使
某
一
个
a
i
加
一
,
但
是
对
应
每
个
a
i
只
能
加
一
一
次
你可以使某一个a_i加一,但是对应每个a_i只能加一一次
你可以使某一个ai加一,但是对应每个ai只能加一一次
加
一
的
时
候
需
要
花
费
b
的
代
价
加一的时候需要花费b的代价
加一的时候需要花费b的代价
问
使
得
数
组
中
相
邻
数
都
不
相
等
,
最
少
需
要
多
少
代
价
问使得数组中相邻数都不相等,最少需要多少代价
问使得数组中相邻数都不相等,最少需要多少代价
题解:
n
<
=
1
e
5
n<=1e5
n<=1e5
这
道
题
我
最
先
想
到
的
就
是
d
f
s
剪
枝
这道题我最先想到的就是dfs剪枝
这道题我最先想到的就是dfs剪枝
因
为
每
个
a
i
只
能
加
一
次
因为每个a_i只能加一次
因为每个ai只能加一次
所
以
只
要
考
虑
这
个
a
i
到
底
加
不
加
所以只要考虑这个a_i到底加不加
所以只要考虑这个ai到底加不加
对
每
种
情
况
判
断
一
下
是
否
可
行
,
进
行
剪
枝
对每种情况判断一下是否可行,进行剪枝
对每种情况判断一下是否可行,进行剪枝
很
明
显
,
这
个
n
的
数
据
范
围
会
导
致
超
时
很明显,这个n的数据范围会导致超时
很明显,这个n的数据范围会导致超时
但
是
其
实
换
一
种
方
法
分
析
但是其实换一种方法分析
但是其实换一种方法分析
每
个
位
置
有
两
种
状
态
,
如
果
只
考
虑
每
个
状
态
的
上
一
个
数
和
他
的
状
态
每个位置有两种状态,如果只考虑每个状态的上一个数和他的状态
每个位置有两种状态,如果只考虑每个状态的上一个数和他的状态
然
后
进
行
转
移
,
这
不
就
是
d
p
问
题
了
然后进行转移,这不就是dp问题了
然后进行转移,这不就是dp问题了
所
以
d
p
[
i
]
[
2
]
前
i
个
数
里
第
i
个
数
是
否
加
的
状
态
的
最
小
代
价
所以dp[i][2]前i个数里第i个数是否加的状态的最小代价
所以dp[i][2]前i个数里第i个数是否加的状态的最小代价
然
后
如
果
上
个
数
加
1
不
等
于
这
个
数
然后如果上个数加1不等于这个数
然后如果上个数加1不等于这个数
d
p
[
i
]
[
0
]
=
d
p
[
i
−
1
]
[
1
]
dp[i][0]=dp[i-1][1]
dp[i][0]=dp[i−1][1]
如
果
上
个
数
不
等
于
这
个
数
加
一
如果上个数不等于这个数加一
如果上个数不等于这个数加一
d
p
[
i
]
[
1
]
=
d
p
[
i
−
1
]
[
0
]
+
b
[
i
]
dp[i][1]=dp[i-1][0]+b[i]
dp[i][1]=dp[i−1][0]+b[i]
用
这
样
可
以
对
两
个
数
的
所
有
状
态
进
行
转
移
用这样可以对两个数的所有状态进行转移
用这样可以对两个数的所有状态进行转移
还
有
除
此
之
外
的
两
种
转
移
详
见
代
码
还有除此之外的两种转移详见代码
还有除此之外的两种转移详见代码
最
后
答
案
就
是
m
i
n
(
d
p
[
n
]
[
1
]
,
d
p
[
n
]
[
0
]
)
最后答案就是min(dp[n][1],dp[n][0])
最后答案就是min(dp[n][1],dp[n][0])
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=911451407;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
ll n,ans=1e18;
ll a[maxn],b[maxn];
ll dp[maxn][2];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
for(int i=1;i<=n;i++)dp[i][1]=dp[i][0]=1e18;
dp[0][0]=0;
for(int i=1;i<=n;i++){
if(a[i]+1!=a[i-1])dp[i][1]=min(dp[i][1],dp[i-1][0]+b[i]);
if(a[i]!=a[i-1]+1)dp[i][0]=min(dp[i][0],dp[i-1][1]);
if(a[i]!=a[i-1])dp[i][0]=min(dp[i][0],dp[i-1][0]);
if(a[i]+1!=a[i-1]+1)dp[i][1]=min(dp[i][1],dp[i-1][1]+b[i]);
}
cout<<min(dp[n][1],dp[n][0]);
return 0;
}
D. 数列统计
题意:
以
x
结
尾
的
长
度
为
l
的
非
降
数
组
有
多
少
种
以x结尾的长度为l的非降数组有多少种
以x结尾的长度为l的非降数组有多少种
题解:
这
道
题
可
以
进
行
一
个
递
推
这道题可以进行一个递推
这道题可以进行一个递推
因
为
长
度
为
l
的
以
x
结
尾
的
数
肯
定
能
从
两
种
数
递
推
因为长度为l的以x结尾的数肯定能从两种数递推
因为长度为l的以x结尾的数肯定能从两种数递推
一
个
是
长
度
为
l
−
1
以
1
到
x
−
1
结
尾
的
数
一个是长度为l-1以1到x-1结尾的数
一个是长度为l−1以1到x−1结尾的数
另
一
个
是
长
度
为
1
到
l
−
1
以
x
结
尾
的
数
另一个是长度为1到l-1以x结尾的数
另一个是长度为1到l−1以x结尾的数
但
是
我
们
一
直
递
推
可
以
减
去
第
二
种
但是我们一直递推可以减去第二种
但是我们一直递推可以减去第二种
我
们
把
第
一
种
改
为
长
度
为
l
−
1
以
1
到
x
结
尾
的
数
我们把第一种改为长度为l-1以1到x结尾的数
我们把第一种改为长度为l−1以1到x结尾的数
这
样
递
推
下
来
就
把
第
二
种
情
况
全
部
覆
盖
这样递推下来就把第二种情况全部覆盖
这样递推下来就把第二种情况全部覆盖
所
以
就
形
成
了
一
个
递
推
式
所以就形成了一个递推式
所以就形成了一个递推式
d
p
[
l
]
[
x
]
=
∑
i
=
1
x
d
p
[
l
−
1
]
[
i
]
dp[l][x]=\sum_{i=1}^xdp[l-1][i]
dp[l][x]=∑i=1xdp[l−1][i]
设
置
好
边
界
值
即
可
使
用
递
推
式
即
可
求
得
结
果
设置好边界值即可使用递推式即可求得结果
设置好边界值即可使用递推式即可求得结果
但
是
我
一
开
始
没
有
想
到
这
个
递
推
式
但是我一开始没有想到这个递推式
但是我一开始没有想到这个递推式
我
用
的
是
打
表
的
方
法
我用的是打表的方法
我用的是打表的方法
这
一
看
,
就
很
明
显
了
,
杨
辉
三
角
这一看,就很明显了,杨辉三角
这一看,就很明显了,杨辉三角
只
不
过
这
个
行
数
是
斜
着
的
,
可
以
算
出
来
只不过这个行数是斜着的,可以算出来
只不过这个行数是斜着的,可以算出来
行
数
就
是
l
+
x
−
1
,
列
就
是
第
l
个
行数就是l+x-1,列就是第l个
行数就是l+x−1,列就是第l个
直
接
用
杨
辉
三
角
公
式
C
n
−
1
m
−
1
代
入
直接用杨辉三角公式C_{n-1}^{m-1}代入
直接用杨辉三角公式Cn−1m−1代入
结
果
就
是
C
l
+
x
−
2
l
−
1
结果就是C_{l+x-2}^{l-1}
结果就是Cl+x−2l−1
逆
元
快
速
幂
什
么
的
计
算
一
下
就
行
了
逆元快速幂什么的计算一下就行了
逆元快速幂什么的计算一下就行了
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=911451407;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
ll fact[maxn],inv1[maxn];
ll Pow(ll a, ll b){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
//逆元
ll inv(ll b){
return Pow(b,mod-2)%mod;
}
ll C(ll n,ll m){
if(m>n||n<0||m<0)return 0;
if(m==0||m==n) return 1;
ll res=(fact[n]*inv1[m]%mod*inv1[n-m])%mod;
return res;
}
void init() {
fact[0] = 1;
for (int i = 1; i < maxn; i++) {
fact[i] = fact[i - 1] * i %mod;
}
inv1[maxn - 1] = Pow(fact[maxn - 1], mod - 2);
for (int i = maxn - 2; i >= 0; i--) {
inv1[i] = inv1[i + 1] * (i + 1) %mod;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int _;
init();
while(cin>>_){
while(_--){
ll l,x;
cin>>l>>x;
cout<<C(l+x-2,x-1)<<endl;
}
}
return 0;
}