四川省大学生程序设计大赛补题

C. Black-White Cubic Lattice

在这里插入图片描述

考点:最小费用流

#include<bits/stdc++.h>

using namespace std;

const int N = 10010, M = 200010, inf = 1e9;
typedef long long ll;

int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];

void add(int a, int b, int c)
{
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

bool bfs()
{
    int hh = 0, tt = 0;
    memset(d, -1, sizeof d);
    q[0] = S, d[S] = 0, cur[S] = h[S];
    while (hh <= tt)
    {
        int t = q[hh ++ ];
        for (int i = h[t]; ~i; i = ne[i])
        {
            int ver = e[i];
            if (d[ver] == -1 && f[i])
            {
                d[ver] = d[t] + 1;
                cur[ver] = h[ver];
                if (ver == T) return true;
                q[ ++ tt] = ver;
            }
        }
    }
    return false;
}

int find(int u, int limit)
{
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        cur[u] = i;
        int ver = e[i];
        if (d[ver] == d[u] + 1 && f[i])
        {
            int t = find(ver, min(f[i], limit - flow));
            if (!t) d[ver] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

ll dinic()
{
    int flow;
    ll r=0;
    while (bfs()) while (flow = find(S, inf)) r += flow;
    return r;
}

int main()
{
    int N,M,L;
	cin>>N>>M>>L; 
    memset(h, -1, sizeof h);
    vector<vector<vector<int>>> c(L,vector<vector<int>>(N,vector<int>(M)));
    vector<vector<string>> s(L,vector<string>(N));
    S=N*M*L+2,T=S+1;
    for(int i=0;i<L;i++){
    	for(int j=0;j<N;j++){
    		cin>>s[i][j];
		}
	}
	for(int i=0;i<L;i++){
		for(int j=0;j<N;j++){
			for(int k=0;k<M;k++){
				cin>>c[i][j][k];
				if(s[i][j][k]=='W'){
					add((i*N+j)*M+k,T,c[i][j][k]);
				}else{
					add(S,(i*N+j)*M+k,c[i][j][k]);
				}
				if(i>0){
					add((i*N+j)*M+k,((i-1)*N+j)*M+k,inf);
				}
				if(j>0){
					add((i*N+j)*M+k,(i*N+j-1)*M+k,inf);
				}
				if(k>0){
					add((i*N+j)*M+k,(i*N+j)*M+k-1,inf);
				}
			}
		}
	}
	add(S,0,inf),add(N*M*L-1,T,inf);
    printf("%lld\n", dinic());
    return 0;
}

G. Function Query

在这里插入图片描述
考点:字典树

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define x first
#define y second
const int N=9e6+10,inf=0x3f3f3f3f;
int tr[N][2],idx=1,f[N];

void add(int x,int id){
	int p=1;
	for(int i=30;i>=0;i--){
		int t=x>>i&1;
		if(tr[p][t]==0){
			tr[p][t]=++idx;
		}
		p=tr[p][t];
		f[p]=min(f[p],id);
	}
}

int query(int a,int b){
	int p=1,ans1=inf,ans2=inf;
	for(int i=30;i>=0;i--){
		int d=a>>i&1;
		int e=b>>i&1;
		if(e){
			//求x^a小于b的最小下标,让x的第i位^a的第i位为0就小于b了,即x的第i位等于a的第i位
			ans1=min(ans1,f[tr[p][d]]);
		}else{
			//求x^a大于b的最小下标 
			ans2=min(ans2,f[tr[p][d^1]]);
		} 
//前面x的位数取值异或a等于b。a^x=b  =>  a^b=x
//p从零开始的话,如果节点没有赋值,则为0,又从根节点开始,这样不行,所以根节点赋值为1才行 
		p=tr[p][d^e];
	}
	ans1=min(ans1,f[p]);//这里再加上等于的情况 
	ans2=min(ans2,f[p]);
	if(ans1==inf||ans2==inf) return -1;
	//如果所有的数都是a^x=b,则下标是第一个即0,这时候答案是1 
	return max(1,max(ans1,ans2));//因为下标从0开始的,所以算是自动-1了max-1 
}

void solve(){
	ios::sync_with_stdio(false);//记得关流,不然会超时,1e5次方的时候 
	cin.tie(0);cout.tie(0); 
	int n,q;cin>>n>>q;
	vector<int> x(n);
	memset(f,0x3f,sizeof f);
	memset(tr,0,sizeof tr);
	idx=1;
	for(int i=0;i<n;i++){
		cin>>x[i];
		add(x[i],i);
	}
	
	while(q--){
		int a,b;cin>>a>>b;
		cout<<query(a,b)<<endl;
	}
}

signed main(){
	int T=1;
//	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

I. Container Scheduling

在这里插入图片描述
考点:构造

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;


void solve(){
	int n,l,h;
	cin>>n>>l>>h;
	vector<int> x(n,-1),y(n,-1),a(n),b(n);//x,y存放每个放置矩形的左下角点坐标,a,b表示矩形的长度 
	set<int> cx{0},cy{0};//表示能存放在x,y轴上的位置 
	
	for(int i=0;i<n;i++){
		cin>>a[i]>>b[i];
		for(auto vx:cx){
			for(auto vy:cy){
				int ok=1;
				if(vx+a[i]>l||vy+b[i]>h){
					continue;
				}
				for(int j=0;j<i;j++){
					//只需要错开即可不重叠,!后表示有重叠部分 
					if(!(x[j]==-1||(vx>=x[j]+a[j]||vx+a[i]<=x[j])||(vy>=y[j]+b[j]||vy+b[i]<=y[j]))){
						ok=0;
						break;
					}
				}
				if(ok){
					x[i]=vx;
					y[i]=vy;
					cx.insert(vx+a[i]);
					cy.insert(vy+b[i]);
					break;
				}
			}
			if(x[i]!=-1){
				break;
			}
		}
		if(x[i]==-1){
			cout<<"-1"<<endl;
		}else{
			cout<<x[i]<<" "<<y[i]<<endl;
		}
	}
	 
}

signed main(){
	int T=1;
//	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

J. Roman Numerals

在这里插入图片描述
考点:DP

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int V[]={0,1,2,3,4,5,6,7,8,9,1,5,10,50,100,500,1000};
typedef long long ll;

void solve(){
	string s;
	cin>>s;
	array<int,17> c;
	for(int i=0;i<17;i++){
		cin>>c[i];
	}
	vector<int> dp(112,inf);
	ll cur=0;
	for(auto _:s){
		int d=_-'0';
		cur=cur*10+d;
		vector<int> ndp(112,inf);
		for(int i=0;i<112;i++){
			for(int j=0;j<17;j++){
				int r=i*10+d-V[j];
				if(0<=r&&r<=111){
					ndp[r]=min(ndp[r],dp[i]+c[j]);
				}
			}
		}
		for(int j=0;j<17;j++){
			ll r=cur-V[j];
			if(0<=r&&r<=111){
				ndp[r]=min(ndp[r],c[j]);
			}
			
		}
		swap(dp,ndp);
	}
	cout<<dp[0]<<"\n";
}

signed main(){
	int T=1;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
} 

K. Element Reaction

在这里插入图片描述
考点:高维前缀和(FMT)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;


signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(0);
	
	int n,m;//m种元素,n个元素序列 
	cin>>m>>n;	
	vector<vector<int>> a(m, vector<int>(m));
//	vector<vector<int>> a(m);
//	for(int i=0;i<m;i++){
//		a[i].resize(m);
//	}
	for(int i=0;i<m;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
		}
	}
	string s;
	cin>>s;
	vector<pair<int,int> > nxt(m);
	for(int i=0;i<m;i++){
		nxt[i]={i,n};
	}
	
	vector<ll> f(1<<m);
	for(int i=n-1;i>=0;i--){
		int mask=0;
		int x=s[i]-'a';
		for(int j=0;j<m;j++){
			if(nxt[j].second==n){
				break;
			}
			int y=nxt[j].first;
			f[mask]+=a[x][y];
			f[mask|1<<x]-=a[x][y];
			f[mask|1<<y]-=a[x][y];
			f[mask|1<<x|1<<y]+=a[x][y];
			if(nxt[j].first==x){
				break;
			} 
			mask|=1<<y;
		}
		int j=0;
		while(nxt[j].first!=x){
			j++;
		}
		nxt.erase(nxt.begin()+j);
		nxt.insert(nxt.begin(),make_pair(x,i));
	}
	
	for(int i=1;i<(1<<m);i*=2){
		for(int j=0;j<(1<<m);j+=2*i){
			for(int k=0;k<i;k++){
				f[i+j+k]+=f[j+k];
			}
		}
	}
	
	for(int i=0;i<(1<<m);i++){
		cout<<f[i]<<" \n"[i==(1<<m)-1];
	}
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值