J题
问题抽象一下就是凑数[1, n]得到m
我采取的策略是先贪心从大向小取至可以二进制拆分。
问题抽象一下就是凑数[1, n]得到m
我采取的策略是先贪心从大向小取至可以二进制拆分。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 100000;
bool vis[maxn + 5];
int ans[maxn + 5];
string s;
void solve(int n, ll m) {
for(int i = n; i < m; --i) {
m -= i;
vis[i] = true;
//printf("n = %d\n", n);
ans[i] = (s[i-1] == '0') ? 1 : 3;
}
for(int i = 0; ; ++i) {
int t = (1 << i);
if(t > m) break;
if(t & m) {
//printf("t = %d\n", t);
ans[t] = (s[t-1] == '0') ? 1 : 3;
vis[t] = true;
}
}
}
int main() {
int T;
cin >> T;
while(T--) {
int n;
cin >> n;
cin >> s;
ll m = (ll)n * (n + 1);
if(m % 4) {
cout << -1 << endl;
continue;
}
m /= 4;
//printf("m = %d\n", m);
memset(vis, 0, sizeof(vis));
solve(n, m);
for(int i = 1; i <= n; ++i) {
if(!vis[i]) {
ans[i] = (s[i-1] == '0') ? 2 : 4;
}
}
for(int i = 1; i <= n; ++i) {
cout << ans[i];
}
cout << endl;
}
return 0;
}
F题
对数据进行排序后,发现分母存在成段相同的情况,于是想到利用前缀和。
发现向下取整直接使用前缀和并不正确,应当将除法一并预处理。
注意内存超限以及最后避免出现负数的处理。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 500005;
int a[maxn], b[maxn], sum[maxn][33];
const int mod = 1000000000;
int main() {
int t;
cin >> t;
while(t--) {
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++i) cin >> a[i];
for(int i = 1; i <= m; ++i) cin >> b[i];
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= 32; ++j) {
sum[i][j] =(sum[i-1][j] + a[i]/j) % mod;
}
}
ll ans = 0;
for(int i = 1; i <= m; ++i) {
int l, r, cnt = 1;
ll z = 0, cur = 1;
while(1) {
l = upper_bound(a + 1, a + 1 + n, cur) - a;
if(l > n) break;
r = upper_bound(a + 1, a + 1 + n, cur * b[i]) - a;
if(l != r) z = (z + sum[r - 1][cnt] - sum[l - 1][cnt]) % mod;
cur *= b[i];
cnt++;
}
ans = (ans + z*i) % mod;
}
cout << (ans + mod) % mod << endl;
}
return 0;
}