XDU2023寒假训练1.14


H.Beacon Towers

发现分界点为使得前缀最大值变化的点。

根据乘法原理,可知答案即为相邻分界点之间距离乘积。

即,假设分界点为 $p_1,p_2,\dots ,p_m$ ,答案即为 $\prod\limits_{i=1}^{m-1}(p_{i+1}-p_i+1)$

代码

#include<bits/stdc++.h>
#define ll long long 
#define N 500010
#define mod 1000000007

using namespace std;

int n,h[N];

void solve() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&h[i]);
    int maxn=h[1],maxid=1;
    ll ans=1;
    for(int i=2;i<=n;i++) {
        if(h[i]>maxn) {
            (ans*=i-maxid+1)%=mod;
            maxn=h[i];
            maxid=i;
        }
    }
    printf("%lld\n",ans);
}

int main() {
    solve();
    return 0;
}

A.Factory Balls

发现 $n,k,m$ 值都很小。

状压 + BFS 。

设 $f[x][y]$ 表示染色符合的状态为 $x$ ,装置使用的状态为 $y$ 时的最小步数。

直接 BFS 即可。

时间复杂度 $O\big(2^{n+m}(kn+m)\big)$ 。

代码

#include<bits/stdc++.h>
#define N 11
#define INF 0x3f3f3f3f
using namespace std;


int n,k,m,c[N],eqp[N][N],f[1<<N][1<<N],st=0;

bool vh[N];
queue<pair<int,int> > q;
void bfs() {
    memset(f,0x3f,sizeof(f));
    q.push(make_pair(st,0));
    f[st][0]=0;
    while(!q.empty()) {
        pair<int,int> u=q.front();q.pop();
        int X=u.first,Y=u.second;
        //cout<<"test"<<X<<" "<<Y<<" "<<f[X][Y]<<endl;
        //system("pause");
        for(int i=0;i<m;i++) {
            int nY=Y^(1<<i);
            if(f[X][nY]>f[X][Y]+1) {
                f[X][nY]=f[X][Y]+1;
                q.push(make_pair(X,nY));
            }
        }
        for(int i=0;i<n;i++) vh[i]=false;
        for(int i=0;i<m;i++) if(Y&(1<<i)) for(int j=1;j<=eqp[i][0];j++) vh[eqp[i][j]]=true;
        //for(int i=0;i<n;i++) cout<<vh[i]<<" ";
        //cout<<endl;
        for(int i=0;i<k;i++) {
            int nX=X;
            for(int j=0;j<n;j++) {
                if(!vh[j]) {
                    if(i==c[j]) nX|=(1<<j);
                    else nX=nX&(((1<<n)-1)^(1<<j));
                }
            }
            if(f[nX][Y]>f[X][Y]+1) {
                f[nX][Y]=f[X][Y]+1;
                q.push(make_pair(nX,Y));
            }
        }
    }
}

void solve() {
    scanf("%d%d%d",&n,&k,&m);
    for(int i=0;i<n;i++) {
        scanf("%d",&c[i]);
        c[i]--;
        if(!c[i]) st|=(1<<i);
    }
    for(int i=0;i<m;i++) {
        scanf("%d",&eqp[i][0]);
        for(int j=1;j<=eqp[i][0];j++) {
            scanf("%d",&eqp[i][j]);
            eqp[i][j]--;
        }
    }
    bfs();
    if(f[(1<<n)-1][0]==INF) printf("-1\n");
    else printf("%d\n",f[(1<<n)-1][0]);
}

int main() {
    solve();
    system("pause");
    return 0;
}

F.Stones 1

把同色的缩成一个点,值取其中最大的。

然后就得到了一个黑白相间的序列,假设长度为 $m$ 。

动手模拟,发现取中间的前 $\lceil \frac{m-2}{2}\rceil$ 大的即可。

因为最多能取 $\lceil \frac{m-2}{2}\rceil$ 个,然后肯定往大的取,发现总有方案可以取到这些大的。

学长的解释:

代码

#include<bits/stdc++.h>
#define ll long long 
#define N 300010

using namespace std;

int n,tot=0;
ll a[N],A[N],ans=0;
char s[N];
vector<ll> val;

void solve() {
	scanf("%d",&n);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	int m=0;
	for(int i=1;i<=n;i++) {
		ll maxn=a[i];	
		while(s[i]==s[i+1]) {
			i++;
			maxn=max(maxn,a[i]);
		}
		A[++tot]=maxn;
	}
	if(tot<=2) printf("0\n");
	else {
		for(int i=2;i<tot;i++) val.push_back(A[i]);
		sort(val.begin(),val.end());
		int num=(tot&1)?(tot-1)/2:(tot-2)/2,sz=val.size();
		for(int i=sz-1;i>=sz-num;i--) ans+=val[i];
		printf("%lld\n",ans);
	}
}

int main() {
	solve();
	return 0;
}

D.Triple Sword Strike

三刀,有两种情况。

一种三刀平行,另一种两刀平行,一刀垂直。

贴学长写的题解。

补题的时候没有看到坐标可以取 $0$ ,导致 RE 了好多发。

一定一定一定要注意数据范围。

代码

#include<bits/stdc++.h>
#define N 1000010

using namespace std;

const int M=1000000;
int n,x[N],y[N],v[N],R[N],C[N];
vector<pair<int,int> > RC[N],CR[N];
multiset<int,greater<> > RR,CC;

void solve() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&x[i],&y[i],&v[i]);
    for(int i=1;i<=n;i++) {
        R[x[i]]+=v[i];
        C[y[i]]+=v[i];
        RC[x[i]].push_back(make_pair(y[i],i));
        CR[y[i]].push_back(make_pair(x[i],i));
    }
    for(int i=0;i<=M;i++) if(R[i]) RR.insert(R[i]);
    for(int i=0;i<=M;i++) if(C[i]) CC.insert(C[i]);
    int ans=0,sumR=0,sumC=0,cntR=0,cntC=0;
    for(multiset<int>::iterator p=RR.begin();p!=RR.end();p++) {
        cntR++;
        sumR+=*p;
        if(cntR==3) break;
    }
    for(multiset<int>::iterator p=CC.begin();p!=CC.end();p++) {
        cntC++;
        sumC+=*p;
        if(cntC==3) break;
    }
    ans=max(sumR,sumC);
    for(int i=0;i<=M;i++) {
        int sz=RC[i].size();
        if(!sz) continue;
        for(int j=0;j<sz;j++) {
            CC.erase(CC.find(C[RC[i][j].first]));
            C[RC[i][j].first]-=v[RC[i][j].second];
            CC.insert(C[RC[i][j].first]);
        }
        int cnt=0,sum=0;
        for(multiset<int>::iterator p=CC.begin();p!=CC.end();p++) {
            cnt++;
            sum+=*p;
            if(cnt==2) break;
        }
        ans=max(ans,sum+R[i]);
        for(int j=0;j<sz;j++) {
            CC.erase(CC.find(C[RC[i][j].first]));
            C[RC[i][j].first]+=v[RC[i][j].second];
            CC.insert(C[RC[i][j].first]);
        }
    }
    for(int i=0;i<=M;i++) {
        int sz=CR[i].size();
        if(!sz) continue;
        for(int j=0;j<sz;j++) {
            RR.erase(RR.find(R[CR[i][j].first]));
            R[CR[i][j].first]-=v[CR[i][j].second];
            RR.insert(R[CR[i][j].first]);
        }
        int cnt=0,sum=0;
        for(multiset<int>::iterator p=RR.begin();p!=RR.end();p++) {
            cnt++;
            sum+=*p;
            if(cnt==2) break;
        }
        ans=max(ans,sum+C[i]);
        for(int j=0;j<sz;j++) {
            RR.erase(RR.find(R[CR[i][j].first]));
            R[CR[i][j].first]+=v[CR[i][j].second];
            RR.insert(R[CR[i][j].first]);
        }
    }
    printf("%d\n",ans);
}

int main() {
    solve();
    system("pause");
    return 0;
}

E. RPS Bubble Sort

思维题。

直接贴题解。

真的 好妙。

代码

#include<bits/stdc++.h>
#define N 500010

using namespace std;

int n,t;
char s[N];
map<char,int> cnt;

bool vh[N];
void solve(int l,int r) {
    char winner,loser;
    if(!cnt['R']) winner='S',loser='P';
    else if(!cnt['S']) winner='P',loser='R';
    else winner='R',loser='S';
    int rk=l;
    for(int i=l;i<=r;i++) if(s[i]==loser) vh[max(rk,i-t)]=true,rk++;
    for(int i=l;i<=r;i++) {
        if(vh[i]) printf("%c",loser);
        else printf("%c",winner);
    }
    cnt[winner]=cnt[loser]=0;
}

void work() {
    scanf("%d%d",&n,&t);
    scanf("%s",s+1);
    int l=1;
    for(int i=1;i<=n;i++) {
        cnt[s[i]]++;
        if(cnt['R']&&cnt['S']&&cnt['P']) {
            cnt[s[i]]--;
            solve(l,i-1);
            l=i;
            cnt[s[i]]++;            
        }
    }
    solve(l,n);
    printf("\n");
}

int main() {
    work();
    return 0;
}

文章作者: HoshiuZ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 HoshiuZ !
  目录