中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)

Problem A. 贵校是构造王国吗 I

思路

官方题解很清晰明了。

image

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int,int>
const int N=1e6+3;
void solve() {
    int n,k;
    cin>>n>>k;
    int dq=1;
    vector<PII>ans;
    set<PII>st;
    ans.push_back({1,1});
    st.insert({1,1});
    dq++;
    int ls=1;
    for (int i = 2; i <=n ; ++i) {
        ans.push_back({i,ls});
        st.insert({i,ls});
        dq++;
        ls++;
        ans.push_back({i,ls});
        st.insert({i,ls});
        dq++;
    }
    ans.push_back({1,n});
    st.insert({1,n});
    dq++;
    if(dq>k){
        for(auto [x,y]:ans){
            cout<<x<<' '<<y<<endl;

        }
        return ;
    }
    else{
        for (int i = 1; i <=n ; ++i) {
            for (int j = 1; j <=n ; ++j) {
                if(st.count({i,j})==0){
                    ans.push_back({i,j});
                    if(ans.size()==k){
                        for(auto [x,y]:ans){
                            cout<<x<<' '<<y<<endl;

                        }
                        return ;
                    }
                }
            }
        }
    }

}
signed main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int t=1;
   //  cin>>t;
    while(t--){
        solve();
    }



    return 0;
}

Problem D. 茶和咖啡

思路

和题解类似。不过我们是用线段树维护前缀最小的物品。

image

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define INF INT_MAX
#define N 200010
#define lc p<<1
#define rc p<<1|1
int n, w[N];
int a[N],b[N];
struct node{
	int l,r;
	PII mi;
}tr[N<<2],tr1[N<<2];
void push_up(int p){
	tr[p].mi=min(tr[lc].mi,tr[rc].mi);
}
void build(int p,int l,int r){
	tr[p]={l,r,{0,0}};
	if(l==r){tr[p]={l,r,{w[l]-b[l],l}};return;}
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	push_up(p);
}
void update(int p,int x,int k){
	if(tr[p].l==x and tr[p].r==x){
		tr[p].mi.first+=k;
		return;
	}
	int mid=tr[p].l+tr[p].r>>1;
	if(x<=mid)update(lc,x,k);
	if(x>mid)update(rc,x,k);
	push_up(p);
}
PII query(int p,int x,int y){
	if(x<=tr[p].l and tr[p].r<=y){
		return tr[p].mi;
	}
	int mid=tr[p].l+tr[p].r>>1;
	PII sum={INF,0};
	if(x<=mid){
		sum=min(sum, query(lc,x,y));
	}
	if(y>mid){
		sum=min( query(rc,x,y),sum);
	}
	return sum;
}

void push_up1(int p){
	tr1[p].mi=min(tr1[lc].mi,tr1[rc].mi);
}
void build1(int p,int l,int r){
	tr1[p]={l,r,{0,0}};
	if(l==r){tr1[p]={l,r,{w[l]-b[l],l}};return;}
	int mid=(l+r)>>1;
	build1(lc,l,mid);
	build1(rc,mid+1,r);
	push_up1(p);
}
void update1(int p,int x,int k){
	if(tr1[p].l==x and tr1[p].r==x){
		tr1[p].mi.first+=k;
		return;
	}
	int mid=tr1[p].l+tr1[p].r>>1;
	if(x<=mid)update1(lc,x,k);
	if(x>mid)update1(rc,x,k);
	push_up1(p);
}
PII query1(int p,int x,int y){
	if(y==0)return {INF,0};
	if(x<=tr1[p].l and tr1[p].r<=y){
		return tr1[p].mi;
	}
	int mid=tr1[p].l+tr1[p].r>>1;
	PII sum={INT_MAX,0};
	if(x<=mid){
		sum=min(sum, query1(lc,x,y));
	}
	if(y>mid){
		sum=min( query1(rc,x,y),sum);
	}
	return sum;
}

void solve(){
	int q;
	cin>>n>>q;
	for (int i = 1; i <=n ; ++i) {
		cin>>w[i];
		a[i]=b[i]=0;
	}
	build(1,1,n);
	for(int i=1;i<=q;i++){
		int x,y;
		cin>>x>>y;
		a[x]+=y;
	}
	b[n+1]=0;
	for(int i=n;i>=1;i--){
		b[i]=a[i]+b[i+1];
	}
	build1(1,1,n);
	int pos=n,s=0;
	int ans=0;
	for(int i=1;i<=n;i++){
		auto[mn,pp]=query1(1,1,pos);
		mn+=s;
		if(pos<n){
			auto[mn1,pp1]=query(1,pos+1,n);
			if(mn1<mn){
				mn=mn1;
				pp=pp1;
			}
		}
		if(pp<=pos){
			pos=pp-1;
			s=b[pp];
		} 
		update(1,pp,INF);
		update1(1,pp,INF);
		ans+=mn;
		cout<<ans<<' ';
	}cout<<endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T=1;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

Problem G. 最大路径

思路

懒得写了,题解写得很清楚,赞

image

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int,int>
const int N=1e6+3;
void solve() {
    int n,m;
    cin>>n>>m;
    int ans=0;
    vector<int>a(n),b(m);
    for (int i = 0; i <n ; ++i) {
        cin>>a[i];
    }
    for (int i = 0; i <m ; ++i) {
        cin>>b[i];
    }
    for (int i = 1; i <n ; ++i) {
        ans+=abs(a[i-1]-a[i]);
    }
    for (int i = 1; i <m ; ++i) {
        ans+=abs(b[i-1]-b[i]);
    }
    cout<<ans<<endl;

}
signed main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int t=1;
   //  cin>>t;
    while(t--){
        solve();
    }



    return 0;
}

Problem J. 维克多词典

思路

子集 DP。

单词长度很小,可以考虑状压DP求答案。

\(dp_S\) 为为学习完 S 的集合长度的单词的最小天数,转移的时候枚举每个 S 的子集即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define int long long
#define double long double
#define LL __int128
#define PII pair<double,double>
#define PIC pair<int,char>
#define endl '\n'
typedef long long ll;
const int N = 1e4 + 10;
int a[100];
vector<int>q;
PII S[N];
vector<int>g[20];
void solve() {
	int n, w;
	cin >> n >> w;
	int t = 0;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		if (!a[x]) {
			t++;
			q.push_back(x);
		}
		a[x]++;
	}
	for(int i=0;i<(1<<t);i++){
		S[i]={1e9,1e9};
		g[__builtin_popcount(i)].push_back(i);
	}
	S[0]={0,0};
	for (int i = 0; i < t; ++i){
		for(auto j:g[i]){
			for(int k=0;k<t;k++){
				if ((j >> k & 1)==0) {
					PII x=S[j];
					if(a[q[k]]+x.second<=w){
						x.second+=a[q[k]];
					}else{
						x.first++;
						x.second=a[q[k]];
					}
					
					S[j^(1<<k)]=min(S[j^(1<<k)],x);
				}
			}
			
		}
	}
		cout<<S[(1<<t)-1].first+(S[(1<<t)-1].second>0)<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t = 1;
//	cin>>t;
	while (t--) {
		solve();
	}

	return 0;
}

posted @ 2024-10-07 17:13  Ke_scholar  阅读(18)  评论(0编辑  收藏  举报