VP中三题,10:06开打
赛后膜了发题解你告诉我这F是搜索???????
我写个毛线的
O
(
l
o
g
10
(
N
)
2
)
O(log_{10}(N)^2)
O(log10(N)2)啊
简要题解:
C裸背包。
#include<bits/stdc++.h>
using namespace std;
int n;
int val[123];
bool vis[10210];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&val[i]);
vis[0] = 1;
for(int i=1;i<=n;++i) {
for(int j=10000;j>=0;--j)
vis[j+val[i]] |= vis[j];
}
int ans = 0;
for(int i=0;i<=10000;++i) {
if(i%10 != 0)
ans = max(ans, vis[i] * i);
}
cout<<ans;
return 0;
}
D:显然可以二分,二分之后先全部减去 m i d ∗ B mid*B mid∗B,然后把 m i d mid mid个 A − B A-B A−B分配下去,看够不够用就好。
#include<bits/stdc++.h>
using namespace std;
int n;
long long A, B;
long long h[100010];
bool check(int mid) {
long long bas = 1ll * mid * B;
long long det = A - B;
long long ans = 0;
for(int i=1;i<=n;++i) {
if(h[i] <= bas)
continue;
else
ans += ((h[i] - bas) + (det - 1)) / det;
}
return ans <= mid;
}
int main() {
scanf("%d%lld%lld", &n, &A, &B);
for(int i=1;i<=n;++i)
scanf("%lld",&h[i]);
long long L = 0, R = 1000000000;
while(R > L) {
long long mid = (L + R) >> 1;
if(check(mid))
R = mid;
else
L = mid + 1;
}
cout<<L;
return 0;
}
/*
5 999999999 1000000000
1
1
1
1
1
*/
E:
先全部减掉一个K,然后变成 “非负和的子段数量”,离散化之后BIT就好。猛WA是因为,我在离散化的时候强行加入了一个0进去,而BIT并没有开到n+1,然后一顿wa。
对了我离散化用map写的, 不要学我(
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, K;
long long a[200010];
long long sum[200010];
namespace BIT {
#define low(k) (k & (-k))
int tree[200010];
void add(int k,int val) {
for(int i=k;i<=n+1;i+=low(i))
tree[i] += val;
}
int query(int k) {
int ret = 0;
for(int i=k;i>0;i-=low(i))
ret += tree[i];
return ret;
}
} using namespace BIT;
namespace lis {
map<long long, int>li;
long long cp[200010];
void run() {
for(int i=1;i<=n;++i)
cp[i] = sum[i];
cp[n+1] = 0;
sort(cp+1,cp+n+2);
int lcnt = 0;
li[cp[1]] = ++lcnt;
for(int i=2;i<=n+1;++i)
if(cp[i] != cp[i-1])
li[cp[i]] = ++lcnt;
return;
}
} using namespace lis;
signed main() {
scanf("%lld%lld",&n,&K);
for(int i=1;i<=n;++i)
scanf("%lld", &a[i]), a[i] -= K;
for(int i=1;i<=n;++i)
sum[i] = sum[i-1] + a[i];
run();
long long ans = 0;
add(li[0], 1);
for(int i=1;i<=n;++i) {
int trans = li[sum[i]];
ans += query(trans);
add(trans, 1);
}
cout<<ans;
return 0;
}
/*
5 999999999 1000000000
1
1
1
1
1
*/
F:赛中不知道错哪儿了,看不到数据qwq
沙雕搜索,不想多说话。
感觉我那玩意修一修能过10^2000
贴个STD。
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
ll Power[20];
ll dfs(ll l , ll r , ll d) {
if(l >= r) {
if(d == 0) return l == r ? 10 : 1;
return 0;
}
if(d % 10 == 0) {
if(l != 1) return 10 * dfs(l + 1 , r - 1 , d / 10);
return 9 * dfs(l + 1 , r - 1 , d / 10);
}
ll differ = d % 10 - 10;//选取的数一定要使l位进1否则取反之后的必定小与改数,那么显然不可能。所以differ是d % 10 - 10
ll next = d - differ + differ * Power[r - l];//这里先让d进一位,然后由于对称性,r位+differ=l位+differ所以选择+ differ * Power[r - l],这样才能满足对称条件
if(l == 1) return (9 + differ) * dfs(l + 1 , r - 1 , abs(next) / 10);
return (10 + differ) * dfs(l + 1 , r - 1 , abs(next) / 10);
}
int main() {
ll d;
cin >> d;
Power[0] = 1;
for(int i = 1 ; i <= 18 ; i++) {
Power[i] = Power[i - 1] * 10;
}
ll ans = 0;
for(int i = 2 ; i <= 18 ; i++) {
ans += dfs(1 , i , d);
}//这里选择18位由于原来的数也就最多9位,如果取得数位数是两倍的话显然是不可能的。
cout << ans << endl;
return 0;
}