赛后总结---Codeforces Round 1064 (Div. 2)(虚拟参赛)

Codeforces Round 1064 (Div. 2)

A. Same Difference

给定一个长度为 \(n\) 的字符串 \(\{s_i\}\),一次操作可以将 \(s_i\) 替换为 \(s_{i+1}\)。求最终使得 \(\{s_i\}\) 内每个字符都相同的最小操作次数。

显然最后一个字符无法被修改,那么只能将其他字符都改成最后一个字符。答案即为 \(\sum [s_i \neq s_n]\)

code
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=101;
const int CH=26;

#define ckmax(x,y) ( x=max(x,y) )
#define ckmin(x,y) ( x=min(x,y) )

inline int read()
{
	int f=1,x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch))  { x=x*10+ch-'0';    ch=getchar(); }
	return f*x;
}

int cnt[CH];

signed main()
{
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
    int qQ=read();
    while(qQ--)
    {
        for(int i=0;i<CH;i++) cnt[i]=0;
        int len=read(),lst=0;
        for(int i=1;i<=len;i++)
        {
            char ch; cin>>ch;
            cnt[lst=ch-'a']++;
        }
        printf("%d\n",len-cnt[lst]);
    }
	return 0;
}

B. Tab Closing

有一个长度为 \(a\) 的浏览器窗口,共有 \(n\) 个网页标签。当窗口有 \(m\) 个网页标签时,

用提供的模拟器试一下可以发现:

  • \(b \leq \dfrac{a}{m}\),只需要把鼠标移到 \(b\) 处,一直原地点击就好了。
  • \(b > \dfrac{a}{m}\),需要把鼠标移到 \(a\) 处,一直点击直到 \(b \leq \dfrac{a}{m}\),在按第一类处理。

简单分讨,答案不会超过 \(2\)。注意第二类请可能有不需要移动的情况,即 \(a==b\)

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N=101100;

#define ckmax(x,y) ( x=max(x,y) )
#define ckmin(x,y) ( x=min(x,y) )

inline int read()
{
	int f=1,x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch))  { x=x*10+ch-'0';    ch=getchar(); }
	return f*x;
}

signed main()
{
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
	int qQ=read();
	while(qQ--)
	{
		int a=read(),b=read(),n=read(),ans=1;
		if(b*n>a && a>b) ans++;
		printf("%lld\n",ans);
	}
	return 0;
}

C. Cyclic Merging

给出一个环形数组,目标为通过合并将其变为一个数。

每次合并可以选择环上相邻的两个数 \(x\)\(y\),将两个数替换为 \(\max(x,y)\),并花费 \(\max(x,y)\) 的代价。

求达成目标所需的最小代价。

谁知道因为没开 \(\text{long long}\) 导致我花了 \(1 \text{h}\) 来调试的痛,后面的题都没得写。

贪心,尽可能用较小的数来进行较多的合并操作。所以把数按从小到大的顺序删去,删去时选择和较小的一边合并。

合并的过程用双向列表维护就好了。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N=201100;

#define ckmax(x,y) ( x=max(x,y) )
#define ckmin(x,y) ( x=min(x,y) )

inline int read()
{
	int f=1,x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch))  { x=x*10+ch-'0';    ch=getchar(); }
	return f*x;
}

int n,ans;
map<int,int> idx;
vector<int> num;
vector<int> pos[N];

struct LIST
{
	int lst,nxt;
	int val;
}p[N];

#define nxt(x) p[x].nxt
#define lst(x) p[x].lst

signed main()
{
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
	int qQ=read();
	while(qQ--)
	{
		int n=read();
		for(int i=1;i<=n;i++)
		{
			int x=( p[i].val=read() );
			p[i].lst=i-1,p[i].nxt=i+1;
			if(!idx.count(x))
			{
				num.push_back(x);
				idx[x]=num.size();
			}
			pos[idx[x]].push_back(i);
		}
		p[1].lst=n,p[n].nxt=1;
		sort(num.begin(),num.end());
		for(int i=0;i<num.size();i++)
		{
			int x=num[i];
			for(int j=0;j<pos[idx[x]].size();j++)
			{
				int u=pos[idx[x]][j];
				ans+=min(p[lst(u)].val,p[nxt(u)].val);
				nxt(lst(u))=nxt(u);
				lst(nxt(u))=lst(u);
			}
		}
		printf("%lld\n",ans-num[ num.size()-1 ]);
		
		ans=0;
		idx.clear(),num.clear();
		for(int i=1;i<=n;i++) pos[i].clear();
	}
	return 0;
}

以下题目为赛后完成

D. Marble Council

给定一个大小为 \(n\) 的可重集 \(\{a\}\),把 \(\{a\}\) 分成任意多个可重集 \(x_i\),对于每个可重集 \(x_i\),将其众数加入到可重集 \(S\),求有多少种不同的可重集 \(S\)

看得出是 DP。

首先,我们可以从一个数是否可能在可重集 \(S\) 中的角度思考。

考虑集合 \(S\) 合法的条件。

对于不在集合 \(S\) 中的元素 \(t\),必须存在至少一种构造,使在每个 \(x_i\) 中,\(t\) 都不为众数。

实际上,只需要对于 $ \forall t \notin S$,都有 $ \sum_{c \in S} cnt_c \geq cnt_t $,就可以找到一种合法构造方案。

等价于满足 \(\sum_{c \in S} cnt_c \geq \max_{t \notin S}(cnt_t)\) 成立,进一步等价于 $\sum_{c \in S} cnt_c \geq \max(cnt) $ 成立。

(分讨 \(\max(cnt)\) 是否在集合 \(S\) 可轻松证明)。

那么这就是一个 01 背包问题,状态数组为 \(dp[ \sum_{c\in S} cnt_c ]\)。答案为 \(\max_{ i \in [\max(cnt),n] } dp[i]\)

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=998244353;
const int N=101100;

#define ckmax(x,y) ( x=max(x,y) )
#define ckmin(x,y) ( x=min(x,y) )

inline int read()
{
	int f=1,x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch))  { x=x*10+ch-'0';    ch=getchar(); }
	return f*x;
}

int n,m,w[N];
int p[N],dp[N];

signed main()
{
	freopen("D.in","r",stdin);
	freopen("D.out","w",stdout);
    int qQ=read();
    while(qQ--)
    {
        memset(dp,0,sizeof(dp)); dp[0]=1;
        memset(p,0,sizeof(p)); m=0;
        memset(w,0,sizeof(w));
        n=read();
        for(int i=1;i<=n;i++) w[i]=read();
        sort(w+1,w+n+1);
        int tmp=0;
        for(int i=1;i<=n;i++)
        {
            if(w[i]!=w[i-1]) m++;
            ckmax(tmp,++p[m]);
        }
        sort(p+1,p+m+1);
        for(int i=1;i<=m;i++)
         for(int j=n;j>=p[i];j--)
           dp[j]=(dp[j]+1LL*p[i]*dp[j-p[i]]%mod)%mod;
        int ans=0;
        for(int i=tmp;i<=n;i++) ans=(ans+dp[i])%mod;
        printf("%lld\n",ans);
    }
	return 0;
}

以下题目尚未解决

E. Binary Wine

F. Path Split

posted @ 2025-11-20 16:46  南北天球  阅读(1)  评论(0)    收藏  举报