Codeforces Round 968 (Div. 2)

vp的,老规矩跳过ab

C:

根据题意我们知道三个不一样的字母连续放一定可以,然后观察样例发现好像把两个不同的字母轮流放也可以。进一步猜测(瞎猜的)发现这个好像只要把不同的挨个放进去就行了(本来以为可能要按数量排序但是似乎根本不用),最后剩下的全放一起也没事。然后就过了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
vector<int>E[maxn];
bool vis[maxn];
void dfs(int u,int fa){
if(E[u].size()==1&&E[u][0]==fa){
vis[u]=1;
//cout<<u<<"mk\n";
return;
}
for(int i:E[u]) if(i!=fa)dfs(i,u);
}
int a[maxn];
map<char,int>mp;
set<char>st;
signed main() {
ios::sync_with_stdio(false);
// ½â³ýcinºÍcoutµÄĬÈϰ󶨣¬À´½µµÍIOµÄ¸ºµ£Ê¹Ð§ÂÊÌáÉý
cin.tie(NULL); cout.tie(NULL);
int t; cin >> t;
while (t--) {
int n;cin>>n;mp.clear();st.clear();
string s,ans="";
cin>>s;
for(int i=0;i<s.size();i++){
mp[s[i]]++;st.insert(s[i]);
}
while(ans.size()<s.size()){
for(char j:st){
if(mp[j])mp[j]--,ans+=j;
}
}
cout<<ans<<"\n";
}
}

D:

D1

对每个序列可以取多次意思就是可以取到第二个没出现过的最小整数。然后根据ans和m的关系进行数学计算即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5+10;
int a[maxn];
vector<int>E[maxn];
signed main() {
ios::sync_with_stdio(false);
// ½â³ýcinºÍcoutµÄĬÈϰ󶨣¬À´½µµÍIOµÄ¸ºµ£Ê¹Ð§ÂÊÌáÉý
cin.tie(NULL); cout.tie(NULL);
int t; cin >> t;
while (t--) {
int n,m;cin>>n>>m;
for(int i=0;i<=n;i++)E[i].clear();
for(int i=1;i<=n;i++){
cin>>a[i];
for(int j=1;j<=a[i];j++){
int x;cin>>x;
E[i].push_back(x);
}
sort(E[i].begin(),E[i].end());
}
int ans=0;
for(int i=1;i<=n;i++){
int nw=0;
for(int j=0;j<a[i];j++){
if(E[i][j]==nw)nw++;
}
nw++;
for(int j=0;j<a[i];j++){
if(E[i][j]==nw)nw++;
}
ans=max(ans,nw);
}
//cout<<ans<<"MK\n";
if(ans>=m){
ans=ans*(m+1);
}
else{
int tmp=ans;
ans=ans*(ans+1);
ans=ans+(tmp+m+1)*(m-tmp)/2;
}
cout<<ans<<"\n";
}
}

D2:

总觉得暴力优化能过。但是并不能。

建图,每个序列只会贡献一条边,由最小未出现值到第二小未出现值建边,每个点出边的数量表示能一次操作到达该点的序列数。所以对于点x,若x出边大于2,则f[x]任意点都可达,否则只有点x可达。

f[x]最小为x。从最大值k开始倒叙dp维护f[x],同时维护t(由出边大于2的点的\(f_{max}\)贡献)

最终一个点的值就是max(f[x],t),复杂度为线性

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
#define pb push_back
const int maxn = 2e5+100;
int f[maxn],a[maxn];
pii b[maxn];
vector<int>E[maxn];
signed main() {
ios::sync_with_stdio(false);
// 解除cin和cout的默认绑定,来降低IO的负担使效率提升
cin.tie(NULL); cout.tie(NULL);
int t; cin >> t;
while (t--) {
int k=0,t=0,sum=0;
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[0];
for(int j=1;j<=a[0];j++)cin>>a[j];
sort(a+1,a+a[0]+1);
int nw=0,j=1;
while(nw>=a[j]&&j<=a[0]){
if(nw==a[j])nw++;
j++;
}
int u=nw;nw++;t=max(u,t);
while(nw>=a[j]&&j<=a[0]){
if(nw==a[j])nw++;
j++;
}
int v=nw;b[i]=mkp(u,v);
//cout<<u<<' '<<v<<endl;
k=max(v,k);
}
for(int i=0;i<=k;i++)f[i]=0,E[i].clear();
for(int i=1;i<=n;i++){
E[b[i].fir].pb(b[i].sec);
}
for(int i=k;i>=0;i--){
f[i]=i;
for(int j:E[i])f[i]=max(f[i],f[j]);
if(E[i].size()>=2)t=max(t,f[i]);
}
for(int i=0;i<=min(k,m);i++){
f[i]=max(f[i],t);
sum+=f[i];
}
if(k<m)sum+=(k+1+m)*(m-k)/2;
cout<<sum<<"\n";
}
}

E:

主要是对题意的理解,所有左区间并的最大值要小于所有右区间的并的最小值。其他的题解写的很清楚了,感觉用不着我写。E1和E2相比难度的提升并不大,做法也没有本质区别。

E1:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
#define pb push_back
const int maxn = 5e3+10;
int a[maxn],dp[maxn][maxn];
signed main() {
ios::sync_with_stdio(false);
// 解除cin和cout的默认绑定,来降低IO的负担使效率提升
cin.tie(NULL); cout.tie(NULL);
int t; cin >> t;
while (t--) {
int n,m;cin>>n>>m;
for(int i=0;i<=n+1;i++){
for(int j=0;j<=i+1;j++){
dp[i][j]=-1e9;
}
a[i]=0;
}
dp[0][0]=0;
while(m--){
int l,r;cin>>l>>r;
a[l]=r;
}
for(int i=1;i<=n;i++){
if(a[i]){
int p=a[i];
for(int j=0;j<i;j++){
for(int k=1;k<=p-i;k++){
dp[p][j+k]=max(dp[p][j+k],dp[i-1][j]+j*(p-i+1-k));
}
}
i=p;
}
else{
for(int j=0;j<=i;j++){
dp[i][j]=dp[i-1][j]+j;
if(j)dp[i][j]=max(dp[i][j],dp[i-1][j-1]);
}
}
}
int ans=0;
for(int i=1;i<n;i++){
ans=max(ans,dp[n][i]+i*(i-1)/2+(n-i)*(n-i-1)/2);
}
cout<<ans<<"\n";
}
}

E2:

posted @   lyrrr  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示