牛客练习赛75

A广义肥波

快速幂模板

/*
 *@author SunLakeWalk
 */
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <limits.h>
#include <sstream>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <set>
//#pragma GCC optimize(2)
//#pragma GCC optimize(3, "Ofast", "inlin")

using namespace std;

#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;

const int N = 100010, INF = 0x3f3f3f3f, mod = 1e9 + 7, base = 131;
const double eps = 1e-6, PI = acos(-1);

LL a, b, m, n;
LL f[N];

LL qmi(LL a, LL b) {
  LL ans = 1;

  while (b) {
    if (b & 1) ans = ans * a % mod;
    a = a * a % mod;
    b >>= 1;
  }

  return ans;
}

void work() {
    cin >> a >> b >> m >> n;

    f[1] = f[2] = m;
    for (LL i = 3; i <= n; i ++ ) {
      LL x = qmi(f[i - 1], a) % mod;
      LL y = qmi(f[i - 2], b) % mod;
      f[i] = x * y % mod;
    }
    cout << f[n] << endl;
}

int main() {

  work();

  return 0;
}

小D和他的魔法石

当k=0时,毫无疑问,他是一个完全背包问题
当k!=0时,我们可以通过交换,将价值最大的魔法,和体积最小的石头的魔法交换,我们只选择当前的石头就好了
但是要注意这里的,k一定要交换完,所以,n=2也是一种特殊情况,交换2 * t + 12 * t 次是不一样的。

/*
 *@author SunLakeWalk
 */
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <limits.h>
#include <sstream>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <set>
//#pragma GCC optimize(2)
//#pragma GCC optimize(3, "Ofast", "inlin")

using namespace std;

#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;

const int N = 1010, INF = 0x3f3f3f3f, mod = 1e9 + 7, base = 131;
const double eps = 1e-6, PI = acos(-1);

int n, m, k;
LL a[N], b[N];
LL f[N];
void work() {
	cin >> n >> m >> k;

	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int i = 1; i <= n; i ++ ) cin >> b[i];

	if (k == 0 || n == 2) {
		if (k % 2) swap(b[1], b[2]);
			for (int i = 1; i <= n; i ++ )
				for (int j = a[i]; j <= m; j ++ )
					f[j] = max(f[j], f[j - a[i]] + b[i]);
			cout << f[m] << endl;
			return;
	}

	LL mina = 1e9, maxb = 0;
	for (int i = 1; i <= n; i ++ ) {
		mina = min(mina, a[i]);
		maxb = max(maxb, b[i]);
	}

	cout << m / mina * maxb << endl;
}

int main() {

  work();

  return 0;
}

C宝石街

还是不多懂这个题
让总用时不超过t的情况下,在连续区间内的和尽可能的大

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define int long long

const int N = 6e7 + 10;

int n, t, type, p;
int a[N], s[N];

signed main() {
  scanf("%lld%lld%lld", &n, &t, &type);

  if (type == 1) {
      for (int i = 1; i <= n; i ++ ) scanf("%lld", &a[i]);
  }
  else {
    scanf("%lld%lld", &a[1], &p);
    for (int i = 2; i <= n; i ++ ) {
      int x = a[i - 1] ^ (a[i - 1] << 13);
      int y = x ^ (x >> 17);
      a[i] = (y ^ (y << 5)) % p + 1;
    }
  }

  /*
  如果从第i个位置拿起一个宝石,走到终点x需要消多少时间呢?
  需要x-i
  那么,我们将时间的当作背包容量,将点i走到终点p所消耗的时间当作物品
  体积。

  所取得宝石,一定是一段连续得区间,如果他在当前拿了,然后在后面再丢掉
  的话,不如一开始就不拿或者少拿。如果他在当前位置拿了,然后走到下一个位置不拿
  同样也是对时间的浪费

  注意不一定要将第i位置的宝石全拿,可以只拿一部分。

  我们枚举终点,然后,双指针走起点。
   */

   for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i];
   int sum = 0, ans = 0;
   for (int r = 1, l = 1; r <= n; r ++ ) {
     sum += s[r - 1] - s[l - 1];
     for (; sum > t && l < r; l ++ )
      sum -= a[l] * (r - l);//满足sum<=t下,sum最大值
    if (l == 1) ans = max(ans, s[r] - s[l - 1]);//sum <= t说明,可以走到r这个位置
    else ans = max(ans, s[r] - s[l - 1] + (t - sum) / (r - l + 1));//
   }

   cout << ans << endl;
}

D减数游戏

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

#define int long long

const int N = 100010, mod = 1e9 + 7;

int n, k;
int a[N];
priority_queue<int, vector<int>, greater<int>> pq;
queue<int> q;
/*
如果没有k,那么不管两数相乘的先后顺序如何,最后结果一定是n个数字的乘积。
所以,最后的结果的变化,一定是因为k的原因。那么我们要做的就是,让k对结果的影响最大。
因为a * b + k为我们处理a,b后所得的新数。我们先处理小的数,可以让k的影响更大
========
这可以通过小根堆来实现,但是,我们需要注意的一点是,每个点的是小于1e9的数,我们要对最终结果取模
但是为了不爆long long,我们要在过程中对处理的数字进行取模运算。这就可能导致原本一个比较大的值
在进行取模运算后,反而变小了,这时我们将他加入队列中,很明显,打破了我们每次取最小的原则。
=======
我们发现,当a * b + k大于数组的最大值后,每次的a * b + k一定大于序列的最大值,满足单调性。
那我们就可以将他放入普通队列中,进行取模运算了。
 */
signed main() {
  scanf("%lld%lld", &n, &k);

  int maxn = 0;
  for (int i = 1; i <= n; i ++ ) {
    scanf("%lld", &a[i]);
    maxn = max(maxn, a[i]);
    pq.push(a[i]);
  }

  while (pq.top() < maxn && pq.size() > 1) {
    int t = pq.top();
    pq.pop();

    int s = pq.top();
    pq.pop();

    pq.push(t * s + k);
  }

  while (pq.size()) {
    q.push(pq.top() % mod);
    pq.pop();
  }

  while (q.size() > 1) {
    int t = q.front();
    q.pop();
    int s = q.front();
    q.pop();

    q.push((s * t + k) % mod);
  }

  cout << q.front() << endl;

  return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值