牛客IOI周赛17-普及组

本博客只包含比赛 后三题 题解(最后一题仅含代码)

B、莫的难题

题目描述
埋和莫曾经是好朋友。埋是文科学霸,而莫却只是一个 OI 蒟蒻。一天,埋碰到一道难题跑来问莫。题目是这样的:有五个数字,分别是 5、2、1、3、9.莫可以取任意数字,每个数字可以取无限次。如:取两个 5,则组合为:55;取 2 与 1,则组合为:21。现在要问你所有组合中第 C(n, m)%1e9+7 (n>=m) 个数有多大?
输入描述:
第 1 行一个数 t,表示询问的次数
接下来 t 行,每行两个数 n, m;详情见题目描述。
数据范围:
对于20%的数据,保证t=1
对于10%的数据,保证n=m
对于所有数据,保证
1<=t<=1000
1<=m<=n<=100
输出描述:
t行,每行一个数字,表示所有组合中第 C(n, m)%1e9+7 (n>=m) 个大的数?
示例1
输入

2
3 2
4 3

输出

3
5

AC代码

#include <bits/stdc++.h>
#define sc(x) scanf("%lld", &(x))
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int mod=1e9+7;
ll n,m,k;
ll f[maxn],inv[maxn];
ll qpow(ll a,ll b) //快速幂
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;
		if(b)a=a*a%mod;
	}
	return ans%mod;
}
void init() //预处理
{
	f[0]=inv[0]=1;
	for(int i=1; i<maxn; i++)
	{
		f[i]=f[i-1]*i%mod;
		inv[i]=qpow(f[i],mod-2);
	}
}
ll C(ll n,ll m)
{
	return f[n]*inv[n-m]%mod*inv[m]%mod;
}
char mp[5]={'1','2','3','5','9'};
int main() {
	init(); 
    ll t;sc(t);
    while (t--) {
        ll n, m; sc(n), sc(m);
        ll a = C(n, m);
        string ans="";
        while(a>0){
            --a;//精髓
            ans+=mp[a%5];
            a/=5;
        }
        reverse(ans.begin(),ans.end());
        cout<<ans<<endl;
    }
    return 0;
}

原题解:而坑点就在于:五进制,但是起点是1,而不是0
我也很好奇,为什么 a-- 后就可以了,好像以前有做过类似的

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,表示最小代价。
输入

4
1 2
2 2
2 3
4 1

输出

2

AC代码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define ll long long
#define INF (int)1e18

inline int read() {
  int x = 0, neg = 1; char op = getchar();
  while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
  while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
  return neg * x;
}
inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int maxn = 2e5 + 10;
int n,a[maxn],b[maxn];
ll dp[maxn][2]; // 0 不+1, 1 加一;
signed main() {
  IO;
  n = read();
  for(int i = 1 ; i <= n ; ++i){
    a[i] = read(),b[i] = read();
    dp[i][0] = dp[i][1] = INF;
  }
  dp[1][0] = 0; dp[1][1] = b[1];
  for(int i = 2; i <= n ; ++i) {
    if (a[i] != a[i - 1]) dp[i][0] = min(dp[i][0], dp[i - 1][0]);
    if (a[i] != (a[i - 1] + 1)) dp[i][0] = min(dp[i][0], dp[i - 1][1]);
    if ((a[i] + 1) != a[i - 1]) dp[i][1] = min(dp[i][1], dp[i - 1][0] + b[i]);
    if ((a[i] + 1) != (a[i - 1] + 1)) dp[i][1] = min(dp[i][1], dp[i - 1][1] + b[i]);
  }
  ll ans = min(dp[n][0],dp[n][1]);
  cout << ans << '\n';
  return 0;
}

四种情况的递推,记住了

D、数列统计

题目描述
求以x结尾的长度为ll的不下降正整数数列一共有多少个。对911451407911451407取模
输入描述:
本题有多组数据。本题有多组数据。
第一行一个正整数T,表示数据组数。
对于每组数据:两个用空格隔开的整数l,x
输出描述:
T行,每行一个答案。
示例1
输入

2
2 1
2 3

输出

1
3

在这里插入图片描述
在这里插入图片描述
AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 911451407;
const int maxn = 100005;
ll fac[2000005];
ll qpow(ll x,ll y){
     x %= mod;
    ll ans = 1;
    while(y){
        if(y&1) ans = ans*x%mod;
        x = x*x%mod;
        y >>= 1;
    }
    return ans;
}
int main(void){
    ios::sync_with_stdio(false);
    fac[0] = 1;
    for(int i = 1 ; i < 2000005 ; ++i) fac[i] = fac[i-1]*i%mod;
    int t;
    cin>>t;
    while(t--){
        ll l,x;
        cin>>l>>x;
        ll ans = fac[x+l-2]*qpow(fac[x-1],911451405)%mod;
        ans = ans*qpow(fac[l-1],911451405)%mod;
        cout<<ans<<endl;
    }
}

略,题目没看懂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值