ARC075简要题解

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 midB,然后把 m i d mid mid A − B A-B AB分配下去,看够不够用就好。

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值