The 3rd Universal Cup. Stage 7: Warsaw 补题

A

太牛了。

复读 jiangly 题解。

先把代价除以二。

\(f_{i,j}\) 表示以 \(j\) 的代价覆盖前 \(i\) 个点最多还能覆盖多少距离。发现只有 \(f_{i,x},f_{i,x+1},f_{i,x+2}\) 的值是有意义的。其中 \(x\) 为覆盖的最小代价。因为 \(f_{i,x+3}\) 一定不优。不如你到下个点再买一张短时票。

类似于 ddp 一样的,把 \(f_{i,x},f_{i,x+1},f_{i,x+2}\) 计入 dp 状态。设 \(dp_{i,A,B,C}\) 表示当前考虑到了 \(a_i\), \(f_{i,x} = A,f_{i,x+1} = B,f_{i,x+2} = C\) 的方案数。统计答案计数考虑只在每次 \(x\) 增加的时候统计答案。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 1e3 + 10;
const int mod = 1e9 + 7;

int a[MAX];

int f[2][80][80][80];


int g[10];

int pre[MAX];

void solve(){
	int n = read();
	pre[0] = 1;
	for(int i = 1; i <= n; i++){
		a[i] = read();
		pre[i] = pre[i - 1] * 2 % mod;
	}
	
	f[0][0][0][0] = 1;
	
	int ans = 0;
	
	for(int i = 1; i <= n; i++){
		for(int A = 0; A <= 75; A++)	for(int B = 0; B <= 75; B++)	for(int C = 0; C <= 75; C++)	f[i & 1][A][B][C] = 0; 
		for(int A = 0; A <= 75; A++){
			for(int B = A; B <= 75; B++){
				for(int C = B; C <= 75; C++){
					if(!f[(i & 1) ^ 1][A][B][C])	continue;
					g[1] = max(0ll, A - (a[i] - a[i - 1])), g[2] = max(0ll, B - (a[i] - a[i - 1])), g[3] = max(0ll, C - (a[i] - a[i - 1])), g[4] = g[5] = g[6] = 0;
					for(int j = 1; j <= 6; j++){
						if(j + 1 <= 6)	g[j + 1] = max(g[j + 1], g[j] + 20);
						if(j + 3 <= 6){
							g[j + 3] = max(g[j + 3], g[j] + 75);
						}
						g[j] = max(g[j], g[j - 1]);
					}
					f[i & 1][g[1]][g[2]][g[3]] = (f[i & 1][g[1]][g[2]][g[3]] + f[(i & 1) ^ 1][A][B][C]) % mod;
					int now = 1;
					while(!g[now])	now++;
					ans = (ans + f[(i & 1) ^ 1][A][B][C] * pre[n - i] % mod * (now - 1) % mod) % mod;
					f[i & 1][g[now]][g[now + 1]][g[now + 2]] = (f[i & 1][g[now]][g[now + 1]][g[now + 2]] + f[(i & 1) ^ 1][A][B][C]) % mod;
				}
			}
		}
	}
	write(ans * 2 % mod), endl;
}

signed main(){
	int t = 1;
	while(t--)	solve();
	return 0;
}

B

简单题。直接钦定左边 ? 或者右边 ? 的都为 \(l=r\) 的节点。然后判断能不能放得下,可不可以填完就好了。

赛时糖丸了,贡献一车罚时。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 4e5 + 10;

struct node{
	int l, r;
	int id;
}; node a[MAX];

bool cmp(node x, node y){
	return x.l < y.l;
}

void solve(){
	int n = read(), L = read();
	int n2 = 0;
	int cnt2 = 0;
	for(int i = 1; i <= n; i++){
		int l = read(), r = read();
		if(l == -1 and r == -1){
			cnt2++;
			continue;
		}
		n2++;
		if(l == -1)	l = r, a[n2].id = 1;
		else if(r == -1)	r = l, a[n2].id = 2;
		else a[n2].id = 3;
		a[n2].l = l, a[n2].r = r;
	}
	if(!n2){
		if(L<cnt2)puts("NIE");
		else puts("TAK");
		return ;
	}
	sort(a + 1, a + n2 + 1, cmp);
	int nowr = 0;
	int cnt4 = 0;
	int lft = L;
	if(a[1].l != 1 and a[1].id != 1){
		cnt4++;
	}
	for(int i = 1; i <= n2; i++){
		if(a[i].l == a[i - 1].l or a[i].r == a[i - 1].r){
			puts("NIE");
			return ;
		}
		if(a[i].l <= nowr){
			puts("NIE");
			return ;
		}
		if(a[i].id == 3 or a[i].id == 2){
			if(a[i - 1].id == 2){
				
			}else if(a[i - 1].id == 3 or a[i - 1].id == 1){
				if(a[i - 1].r != a[i].l - 1){
					cnt4++;
				}
			}
		}else{
			
		}
		lft -= a[i].r - a[i].l + 1;
		nowr = a[i].r;
	}
	if(a[n2].r != L and a[n2].id != 2){
		cnt4++;
	}
	if(cnt4 > cnt2){
		puts("NIE");
		return ;
	}
	if(lft < cnt2){
		puts("NIE");
		return ;
	}
	puts("TAK");
	return ;
}

signed main(){
	int t = read();
	while(t--)	solve();
	return 0;
}

C

还不会

D

ucup 场上过的第一题,感动。

这个直接挨个判断能不能成为中位数就行了吧。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 2e5 + 10;

int a[MAX];
map <int, int> mk;

void solve(){
	int n = read(), k = read(), m = read();
	for(int i = 1; i <= n; i++){
		a[i] = read();
	}
	sort(a + 1, a + n + 1);
	if(k % 2){
		bool fl = 0;
		for(int i = 1; i <= n; i++){
			if(a[i] == m){
				if(i - 1 >= k / 2 and n - i >= k / 2){
					fl = 1;
					break;
				}
			}
		}
		if(fl){
			puts("TAK");
		}else{
			puts("NIE");
		}
	}else{
		bool fl = 0;
		for(int i = 1; i <= n; i++){
			if(mk.count(2 * m - a[i])){
				// write(i), endl;
				if(mk[2 * m - a[i]] - 1 >= k / 2 - 1 and n - i >= k / 2 - 1){
					fl = 1;
					break;
				}
			}
			mk[a[i]] = i;
		}
		if(fl){
			puts("TAK");
		}else{
			puts("NIE");
		}
	}
	mk.clear();
}

signed main(){
	int t = read();
	while(t--)	solve();
	return 0;
}

E

金钩爷跟我说这题存在最短路做法,膜拜。

但是可以直接看路径存在的条件,发现相邻两个村庄距离不能小于 2。然后直接最小割。

点击查看代码
	#include<bits/stdc++.h>
	using namespace std;
	const long long inf = 1e18;
	const int mininf = 1e9 + 7;
	#define int long long
	#define pb emplace_back
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
	inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
	#define put() putchar(' ')
	#define endl puts("")
	const int MAX = 6e3 + 10;
	int psz = 2;
	
	struct flow{
		struct node{
			int v, w, cp;
		}; vector <node> g[MAX];
		
		int dis[MAX];
		
		bool bfs(int s, int t){
			for(int i = 1; i <= psz; i++)	dis[i] = mininf;
			dis[s] = 0;
			queue <int> q;
			q.push(s);
			while(!q.empty()){
				int u = q.front();
				q.pop();
				for(auto V : g[u]){
					if(V.w > 0 and dis[V.v] > dis[u] + 1){
						dis[V.v] = dis[u] + 1;
						q.push(V.v);
					}
				}
			}
			if(dis[t] == mininf)	return 0;
			return 1;
		}
		
		int cur[MAX];
		
		int aug(int u, int now, int t){
			if(u == t)	return now;
			int ans = 0;
			for(int &i = cur[u]; i < g[u].size(); i++){
				int v = g[u][i].v, w = g[u][i].w, cp = g[u][i].cp;
				if(dis[v] != dis[u] + 1)	continue;
				int ret = aug(v, min(w, now), t);
				g[u][i].w -= ret, g[v][cp].w += ret;
				now -= ret, ans += ret;
				if(now <= 0)	break;
			}
			return ans;
		}
		
		void add_edge(int u, int v, int w){
			g[u].pb(node{v, w, g[v].size()});
			g[v].pb(node{u, 0, g[u].size() - 1});
		}
	}; flow G;
	      
	int id[55][55][2];
	
	int a[55][55];
	
	
	void solve(){
		int n = read(), m = read();
		int s = 1, t = 2;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= m; j++){
				char ch = getchar();
				while(ch != '.' and ch != '#'){
					ch = getchar();
				}
				if(ch == '#'){
					a[i][j] = 1;
					id[i][j][0] = ++psz, id[i][j][1] = ++psz;
				}
			}
		}
		for(int i = 1; i <= m; i++)	if(a[1][i])	G.add_edge(id[1][i][1], t, inf);
		for(int i = 1; i <= n; i++)	if(a[i][1])	G.add_edge(s, id[i][1][0], inf);
		for(int i = 1; i <= m; i++)	if(a[n][i])	G.add_edge(s, id[n][i][0], inf);
		for(int i = 1; i <= n; i++)	if(a[i][m])	G.add_edge(id[i][m][1], t, inf);
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= m; j++){
				if(!a[i][j])	continue;
				G.add_edge(id[i][j][0], id[i][j][1], 1);
				for(int k = max(1ll, i - 2); k <= min(n, i + 2); k++){
					for(int k2 = max(1ll, j - 2); k2 <= min(m, j + 2); k2++){
						if(k == i and k2 == j)	continue;
						if(a[k][k2]){
							G.add_edge(id[i][j][1], id[k][k2][0], inf);
						}
					}
				}
			}
		}
		int ans = 0;
		while(G.bfs(s, t)){
			for(int i = 1; i <= psz; i++)	G.cur[i] = 0;
			ans += G.aug(s, inf, t);
		}
		write(ans), endl;
	}
	
	signed main(){
		int t = 1;
		while(t--)	solve();
		return 0;
	}

F

这题是真的垃圾。考虑到斐波那契数列增长很快啊。所以我们对于每一个数 \(a\) 只需要枚举比它大一个的斐波那契数即可。

然后你要估算对应的数是斐波那契数第几项。。。。。

G

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 55;

int a[MAX][MAX];

void solve(){
	int n = read();
	int ans = 0;
	for(int i = 1; i <= n; i++){
		int cnt =  inf;
		for(int j = 1; j <= n; j++){
			a[i][j] = read();
			cnt = min(cnt, a[i][j]);
		}
		ans = max(ans, cnt);
	}
	write(ans), endl;
}

signed main(){
	int t = 1;
	while(t--)	solve();
	return 0;
}

HI 不会

J

直接 dp 就好了。

L

随机的话,发现其实能拼成的概率不大,所以只需要枚举一些就好了。

G

直接做

posted @ 2024-09-14 16:15  WRuperD  阅读(100)  评论(0编辑  收藏  举报

本文作者:DIVMonster

本文链接:https://www.cnblogs.com/guangzan/p/12886111.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

这是一条自定义内容

这是一条自定义内容