吉林大学ACM集训队选拔赛 全部题解

链接

文章目录

A

= 7 、 > 7 、 < 7 =7、>7、<7 =7>7<7三种情况,对每一位为7其他位对此位的贡献进行计算

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e5+10;
const int mod = 1e9+7;

int t;
ll a[N];
string s;
ll p[N];

void init(){
	p[0] = 1;
	for(int i = 1; i < N; i++){
		p[i] = p[i-1]*10%mod;
	}
}

int main(){
	IO;
	cin >> t;
	init();
	while(t--){
		cin >> s;
		int n = s.size();
		for(int i = 0; i < n; i++){
			if(i == 0) a[i] = s[i]-'0';
			else a[i] = (a[i-1]*10 + s[i] - '0') % mod;
		}
		ll ans = 0;
		for(int i = n-1; i >= 0; i--){
			ll l;
			if(i == 0) l = 1;
			else l = a[i-1] + 1;
			ll r = (a[n-1] - a[i]*p[n-1-i]%mod + 1 + mod) % mod;
			if(s[i] == '7'){
				ans += r + (l-1+mod)%mod * p[n-1-i] % mod;
			}
			else if(s[i] > '7'){
				ans += l * p[n-1-i] % mod;
			}
			else {
				ans += (l-1+mod)%mod * p[n-1-i] % mod;
			}
			ans %= mod;
		}
		cout << ans << "\n";
	}
	return 0;
}

B

d p [ i ] [ j ] dp[i][j] dp[i][j] i i i 位中选取若干数字后模 5 5 5 j j j 的最大值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e6+10;
const int mod = 1e9+7;

int n, a[N];
ll dp[N][5];

int main(){
	IO;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
	}
	dp[0][0] = 0;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < 5; j++){
			dp[i+1][j] = dp[i][j];
		}
		for(int j = 0; j < 5; j++){
			if(dp[i][j]%5 == j){
				dp[i+1][(j+a[i+1])%5] = max(dp[i+1][(j+a[i+1])%5], dp[i][j] + a[i+1]);
			}
		}
	}
	cout << dp[n][0] << "\n";
	return 0;
}

C

d p [ i ] dp[i] dp[i] 表示影响 i i i 的所有开关的二进制表示, 使用bitset
使用拓扑排序进行 d p dp dp ,初始 d p [ 1 ] [ 1 ] = 1 dp[1][1] = 1 dp[1][1]=1, 从 u − > v u -> v u>v , 首先影响 u u u的开关一定影响 v v v, 所以 d p [ v ] ∣ = d p [ u ] dp[v] |= dp[u] dp[v]=dp[u]
d [ v ] = = 0 d[v] == 0 d[v]==0 , 即影响v的点已经全部统计到 d p [ v ] dp[v] dp[v] 中,if 影响v的开关数量为奇数, 那么在这些开关的作用下,v打开( d p [ v ] . s e t ( v ) dp[v].set(v) dp[v].set(v) ),需要将v关闭( a n s + + ans++ ans++ )

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 4e4+10;
const int mod = 1e9+7;

int n, m;
vector<int> g[N];
int d[N], ans;
bitset<N> dp[N];
void tobo(){
	queue<int> q;
	for(int i = 1; i <= n; i++){
		if(!d[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(auto v:g[u]){
			d[v]--;
			dp[v] |= dp[u];
			if(!d[v]){
				if(dp[v].count()&1){
					ans++;
					dp[v].set(v);
				}
				q.push(v);
			}
		}
	}
}


int main(){
	IO;
	cin >> n >> m;
	int u, v;
	for(int i = 0; i < m; i++){
		cin >> u >> v;
		g[u].push_back(v);
		d[v]++;
	}
	ans = 1;
	dp[1].set(1);
	tobo();
	cout << ans << "\n";
	return 0;
}

D

筛出每个数因子和,再前缀和

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e6+10;
const int mod = 1e9+7;

int q, l, r;
ll p[N];

void init(){
	p[1] = 1;
	for(int i = 2; i < N; i++){
		p[i] = i+1;
	}
	for(int i = 2; i < N; i++){
		
		if(i > N/i) continue;
		for(int j = i*i; j < N; j += i){
			p[j] += i;
			if(i != j/i){
				p[j] += j/i;
			}
		}
		
	}
	for(int i = 2; i < N; i++){
		p[i] += p[i-1];
	}
}

int main(){
	IO;
	init();
	cin >> q;
	while(q--){
		cin >> l >> r;
		cout << p[r] - p[l-1] << "\n";
	}
	return 0;
}

E

先求出最小 ∑ ( a i ⊕ k ) ∑(a_i⊕k) (aik) 和 此条件下最大的k,
然后从高位往低位贪心取, 求出最大的 k 。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e5+10;
const int mod = 1e9+7;

int n, a[N], q, b[100];
ll m;

int main(){
	IO;
	cin >> n;
	for(int i = 0; i < n; i++){
		cin >> a[i];
		for(int j = 0; j <= 30; j++){
			if((a[i]>>j) & 1) b[j]++;
		}
	}
	ll mn = 0; int k = 0;
	for(int i = 0; i <= 30; i++){
		mn += (1ll<<i)*min(b[i], n-b[i]);
		if(b[i] >= n - b[i]) k |= (1<<i);
	}
	cin >> q;
	while(q--){
		cin >> m;
		if(m < mn){
			cout << "-1\n";
			continue;
		}
		ll sum = mn, kk = k;
		for(int i = 50; i >= 0; i--){
			if((kk>>i) & 1) continue;
			if(sum - (1ll<<i)*b[i] + (__int128)(1ll<<i)*(n-b[i]) <= m){
				kk |= (1ll<<i);
				sum = sum - (1ll<<i)*b[i] + (__int128)(1ll<<i)*(n-b[i]);
			}
		}
		cout << kk << "\n";
	}
	return 0;
}

F

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 100+10;
const int mod = 1e9+7;

int n, a[N], p[N];

int main(){
	IO;
	cin >> n;
	for(int i = 0; i < n; i++){
		cin >> a[i];
	}
	for(int j = 0; j < n; j++){
		cin >> p[j];
	}
	double ans = 0;
	for(int i = 0; i < n; i++){
		ans += p[i]*a[i];
	}
	ans = ans * 4 / 10000;
	if(ans < 4.00+0.001 && ans > 4.00 - 0.001){
		cout << "Yes\n";
	}
	else cout << "No\n";
	return 0;
}

G

计算每个数字对答案的贡献
先看 s l , r = ∑ i = l r ∑ j = i r a i ∗ b j s_{l,r}=∑_{i=l}^r∑_{j=i}^ra_i*b_j sl,r=i=lrj=iraibj,令 i = 1,r = 1、2、3、… 、n
a 1 ∗ b 1 a_1*b_1 a1b1
a 1 ∗ ( b 1 + b 2 ) a_1*(b_1+b_2) a1(b1+b2)

a 1 ∗ ( b 1 + b 2 + . . . + b n ) a_1*(b_1+b_2+...+b_n) a1(b1+b2+...+bn)
可以得到,每个 b i b_i bi出现(n-i+1)次, b i = b i ∗ ( n − i + 1 ) b_i = b_i*(n-i+1) bi=bi(ni+1), 求后缀和,
∑ l = 1 n ∑ r = l n s l , r ∑_{l=1}^n∑_{r=l}^ns_{l,r} l=1nr=lnsl,r, 可以得到 a i ∗ b i a_i*b_i aibi出现 i 次(求出后缀和后的 b i b_i bi);
所以答案为 ∑ a i ∗ b i ∗ i ∑a_i*b_i*i aibii

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e6+10;
const int mod = 998244353;

int n;
ll a[N], b[N];


int main(){
	IO;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
	}
	for(int i = 1; i <= n; i++){
		cin >> b[i];
	}
	for(int i = n; i >= 1; i--){
		b[i] = (b[i] * (n-i+1) % mod + b[i+1]) % mod;
	}
	ll ans = 0;
	for(int i = 1; i <= n; i++){
		ans = (ans + a[i]*b[i]%mod*i) % mod;
	}
	cout << ans << "\n";
	return 0;
}

H

将方程化简可以得到 1 A = 4 ∑ i = l r a i c i \frac{1}{A} = 4\sum _{i=l}^ra_ic_i A1=4i=lraici, 线段树维护

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e5+10;
const int mod = 1e9+7;

int n, q, a[N];
ll sum[N*4];

void up(int o, int l, int r, int pos, int v){
	if(l == r){
		sum[o] += a[l] * v;
		return ;
	}
	int mid = l+r>>1;
	if(pos <= mid) up(o<<1, l, mid, pos, v);
	else up(o<<1|1, mid+1, r, pos, v);
	sum[o] = sum[o<<1] + sum[o<<1|1];
}

ll qu(int o, int l, int r, int ql, int qr){
	if(ql <= l && qr >= r){
		return sum[o];
	}
	ll res = 0;
	int mid = l+r>>1;
	if(mid >= ql) res += qu(o<<1, l, mid, ql, qr);
	if(mid < qr) res += qu(o<<1|1, mid+1, r, ql, qr);
	return res;
}


int main(){
	IO;
	cin >> n >> q;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
	}
	int c;
	for(int i = 1; i <= n; i++){
		cin >> c;
		up(1, 1, n, i, c);
	}
	int opt, l, r;
	while(q--){
		cin >> opt >> l >> r;
		if(!opt){
			up(1, 1, n, l, r);
		}
		else{
			cout << 4*qu(1, 1, n, l, r) << "\n";
		}
	}
	return 0;
}

I

求多源最短路,然后遍历每条边,当边上两点的距离大于边的长度时,找到火停的位置,取max

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e5+10;
const int mod = 1e9+7;

int n, m, s[N];
struct Edge{
	int to, next, w;
}e[N*2];
int head[N], tot = 0;
void addEdge(int u, int v, int w){
	e[tot] = (Edge){v, head[u], w};
	head[u] = tot++;
}

priority_queue< pair<ll, int> > q;
int vis[N];
ll d[N];
void Dij(){
	for(int i = 0; i <= n; i++){
		d[i] = 1e18;
	}
	for(int i = 0; i <= m; i++){
		d[s[i]] = 0;
		q.push(mk(0, s[i]));
	}
	while(!q.empty()){
		int u = q.top().second; q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = head[u]; i != -1; i = e[i].next){
			int v = e[i].to;
			if(d[v] > d[u] + e[i].w){
				d[v] = d[u] + e[i].w;
				q.push(mk(-d[v], v));
			}
		}
	}
}

int main(){
	IO;
	cin >> n >> m;
	memset(head, -1, sizeof(int)*(n+1));
	int u, v, w;
	for(int i = 0; i < n-1; i++){
		cin >> u >> v >> w;
		addEdge(u, v, w);
		addEdge(v, u, w);
	}
	for(int i = 0; i < m; i++){
		cin >> s[i];
	}
	Dij();
	ll ans = 0;
	int t1 = 1, t2 = 1;
	for(int i = 1; i <= n; i++){
		for(int j = head[i]; j != -1; j = e[j].next){
			int v = e[j].to, w = e[j].w;
			if(abs(d[i] - d[v] == w)) ans = max({ans, 2*d[v]});
			else ans = max(ans, max(2*d[i], 2*d[v]) + (w-abs(d[i]-d[v])));
		}
	}
	cout << ans << "\n";
	return 0;
}

J

拆点限制流量的无向图最大流

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 400+10;
const int INF = 1e9;
const int mod = 1e9+7;

int n, m, s, t;
struct Edge{
	int to, next, c, f;
}e[5000];
int head[N], tot = 0;
void addEdge(int u, int v, int c, int f){
	e[tot] = (Edge){v, head[u], c, f};
	head[u] = tot++;
}

int d[N];
int cur[N];
int bfs(){
	memset(d,-1,(2*n+1) * sizeof(int));
	queue<int>Q;
	Q.push(s);
	d[s] = 0;
	while(!Q.empty())
	{
		int u = Q.front(); Q.pop();
		for(int i = head[u]; i != -1; i = e[i].next)
		{
			int v = e[i].to;
			if(d[v] == -1 && e[i].c > e[i].f)
			{
				d[v] = d[u] + 1;
				if(v == t) return 1;
				Q.push(v);
			}
		}
	}
	return 0;
}

int dfs(int u,int a){
	if(u == t || a == 0)return a;
	int flow = 0, f;
	for(int &i = cur[u]; i != -1; i = e[i].next)
	{
		int v = e[i].to;
		if(d[u]+1 == d[v] && ( f= dfs(v, min(a,e[i].c-e[i].f) ) ) > 0)
		{
			e[i].f += f;
			e[i^1].f -= f;
			flow += f;
			a -= f;
			if(a==0) break;
		}
	}
	return flow;
}

ll Maxflow(){
	ll flow = 0;
	while(bfs())
	{
		for(int i = 1; i <= 2*n; i++){
			cur[i] = head[i];
		}
		flow += dfs(s,INF);
	}
	return flow;
}

int main(){
	IO;
	cin >> n >> m;
	memset(head, -1, sizeof(int)*(n*2+1));
	int a;
	for(int i = 1; i <= n; i++){
		cin >> a;
		addEdge(i, i+n, a, 0);
		addEdge(i+n, i, 0, 0);

		addEdge(i+n, i, a, 0);
		addEdge(i, i+n, 0, 0);
	}
	int u, v, c;
	for(int i = 1; i <= m; i++){
		cin >> u >> v >> c;
		addEdge(u+n, v, c, 0);
		addEdge(v, u+n, 0, 0);

		addEdge(v+n, u, c, 0);
		addEdge(u, v+n, 0, 0);
	}
	int size;
	cin >> s >> size;
	t = 1;
	cout << fixed << setprecision(6) << size*1.0/Maxflow() << "\n";
	return 0;
}

K

sg[sta]表示某个子集的必胜/必败态

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 100+10;
const int mod = 1e9+7;

int n, x[N], y[N], X[N], Y[N];
int sg[1<<16];

int check(int a){
	int cnt = 0;
	for(int i = 0; i < n; i++){
		if(a & (1<<i))
			X[++cnt] = x[i], Y[cnt] = y[i];
	}
	if(cnt <= 2) return 1;
	for(int i = 3; i <= cnt; i++){
		if(1ll*(X[i]-X[1])*(Y[2]-Y[1]) != 1ll*(X[2]-X[1])*(Y[i]-Y[1])){
			return 0;
		}
	}
	return 1;
}

int dfs(int cur){
	if(sg[cur] != -1) return sg[cur];
	if(check(cur)){
		return sg[cur] = 1;
	}
	for(int i = (cur-1)&cur; i; i = (i-1)&cur){
		if(check(cur^i)==1 && dfs(i) == 0)
			return sg[cur] = 1;
	}
	return sg[cur] = 0;
}

int main(){
	IO;
	cin >> n;
	int m = 1 << n;
	for(int i = 0; i < n; i++){
		cin >> x[i] >> y[i];
	}
	memset(sg, -1, sizeof(sg));
	sg[0] = 0;
	if(dfs(m-1))
        cout << "zyh\n";
    else
        cout << "fzj\n";
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值