中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)
中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)
Problem A. 贵校是构造王国吗 I
思路
官方题解很清晰明了。
代码
#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. 茶和咖啡
思路
和题解类似。不过我们是用线段树维护前缀最小的物品。
代码
#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. 最大路径
思路
懒得写了,题解写得很清楚,赞
代码
#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;
}