牛客 周赛102 20250806
牛客 周赛102 20250806
https://ac.nowcoder.com/acm/contest/114111
A:
题目大意:
void solve(){
int n;
cin>>n;
cout<<2<<endl;
}
签到
B:
题目大意:
给定包含三个 \(1\) 的 \(01\) 字符串,判断两个相邻 \(1\) 之间的距离是否相同
void solve(){
int n;
cin>>n;
string s;
cin>>s;
int st=0;
int cnt1=0,cnt2=0;
for (auto c:s){
if (c=='1'&&st==0)
st=1;
else if (c=='1'&&st==1)
st=2;
else if (c=='1'&&st==2)
break;
if (c=='0'&&st==1) cnt1++;
if (c=='0'&&st==2) cnt2++;
}
if (cnt1==cnt2) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
模拟
C:
题目大意:
void solve(){
int n;
cin>>n;
string s;
cin>>s;
vector<int> a,b;
for (auto c:s) a.push_back(c-'0'),b.push_back(c-'0');
int cnt1=0,cnt2=0;
for (int i=0;i<n-1;i++){
if (i%2==0&&a[i]!=1){
a[i]^=1;
a[i+1]^=1;
cnt1++;
}
if (i%2==1&&a[i]!=0){
a[i]^=1;
a[i+1]^=1;
cnt1++;
}
}
bool f1=1;
for (int i=1;i<n;i++){
if (a[i]==a[i-1]) f1=0;
}
for (int i=0;i<n-1;i++){
if (i%2==0&&b[i]!=0){
b[i]^=1;
b[i+1]^=1;
cnt2++;
}
if (i%2==1&&b[i]!=1){
b[i]^=1;
b[i+1]^=1;
cnt2++;
}
}
bool f2=1;
for (int i=1;i<n;i++){
if (b[i]==b[i-1]) f2=0;
}
if(f1&&f2) cout<<min(cnt1,cnt2)<<endl;
else if (f1) cout<<cnt1<<endl;
else if (f2) cout<<cnt2<<endl;
else cout<<-1<<endl;
}
有且仅有两种可能 \(0101\cdots,1010\cdots\),分别判断这两种情况是否能合法得到
贪心的,如果存在一个前缀串符合这样的形式,那么修改这个前缀串一定劣
D:
题目大意:
void solve(){
int n;
cin>>n;
string s;
cin>>s;
s=' '+s;
vector<int> cnt(n+1,0);
for (int i=1;i<=n;i++) cnt[i]=cnt[i-1]+(s[i]=='1');
int ans=1e9;
for (int i=1;i<n;i++){
for (int j=i+1;j<n;j++){
for (int k=j+1;k<n;k++){
int A1=cnt[i]-cnt[0];
int B1=cnt[j]-cnt[i];
int C1=cnt[k]-cnt[j];
int D1=cnt[n]-cnt[k];
int A0=i-A1;
int B0=(j-i)-B1;
int C0=(k-j)-C1;
int D0=(n-k)-D1;
int res=min(A1+B0+C1+D0,A0+B1+C0+D1);
ans=min(ans,res);
}
}
}
cout<<ans;
}
考虑符合要求的字符串只有 \(0101,1010\) 形式的符合要求,连续的 \(1\) 和 \(0\) 对答案的的贡献可以看作只有一个 \(1\) 或 \(0\)
所以枚举三个分割点,计算总代价最小的方案,时间复杂度 \(O(n^3)\)
E:
题目大意:
const int N=2e5+10;
int dp[N];
void init(){
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for (int i=1;i<=sqrt(2*N)+1;i++)
for (int j=1;j<=N;j++)
if (i*(i+1)/2<=j)
dp[j]=min(dp[j],dp[j-i*(i+1)/2]+i+1);
}
void solve(){
int k;
cin>>k;
cout<<dp[k]-1<<endl;
}
类似背包问题,在限定容量为 \(k\) 的背包中选取体积最小的方案
\(dp_{i,j}\) 表示从前 \(i\) 个物品选出权值为 \(j\) 的物品组合的最小体积,和 01 背包一样,可以优化掉第一维度
长为 \(n\) 的连续 \(1\) 字符串产生的贡献为 \(n(n+1)/2\) ,所以至多有 \(\sqrt n\) 个物品可以选择,时间复杂度为 \(O(n\sqrt n)\)
注意需要加上隔开连续 \(1\) 字符串的 \(0\) 字符的数量
F:
题目大意:
const int N=2e5+10;
int dp[N];
int last[N];
void init(){
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for (int i=1;i<=sqrt(2*N)+1;i++){
for (int j=1;j<=N;j++){
if (i*(i+1)/2<=j){
if (dp[j]>dp[j-i*(i+1)/2]+i+1){
dp[j]=dp[j-i*(i+1)/2]+i+1;
last[j]=i;
}
}
}
}
}
void solve(){
int k;
cin>>k;
string s;
while (k){
for (int i=1;i<=last[k];i++) s+='1';
s+='0';
k-=last[k]*(last[k]+1)/2;
}
s.erase(s.end()-1);
cout<<s<<endl;
}
用 \(last\) 数组记录状态转移的方向,不改变时间复杂度,输出方案时从后往前递推状态
G:
题目大意:
std::mt19937_64 rng;
LL getrand(int l,int r){
std::uniform_int_distribution<LL> distribution(l,r);
return distribution(rng);
}
const int N=2e5+10;
struct que{
int l,r,id;
};
void solve(){
int n,m;
cin>>n>>m;
vector<int> a(n+1);
vector<LL> h(N);
vector<LL> prexor(n+1);
for (int i=1;i<=n;i++) cin>>a[i];
vector<__int128> sum(n+1), ssum(n+1), sssum(n+1);
for(int i=1;i<=n;i++){
sum[i] = sum[i-1] + a[i];
ssum[i] = ssum[i-1] + (__int128)a[i]*a[i];
sssum[i] = sssum[i-1] + (__int128)a[i]*a[i]*a[i];
}
for (int i=1;i<N;i++) h[i]=getrand(1,1e18);
for (int i=1;i<=n;i++) prexor[i]=h[a[i]]^prexor[i-1];
for (int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
int d=r-l+1;
int dd=d/2;
if (d%2){
cout<<"No"<<endl;
continue;
}
if (dd<=500){
vector<int> cnt(N);
bool f=1;
for (int j=l;j<=r;j++) cnt[a[j]]++;;
for (int j=1;j<=dd;j++){
if (cnt[j]!=2){
f=0;
break;
}
}
if (f) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}else{
if ((prexor[r]^prexor[l-1])!=0){
cout<<"No"<<endl;
continue;
}
if ((__int128)dd*(dd+1)!=sum[r]-sum[l-1]){
cout<<"No"<<endl;
continue;
}
if ((__int128)dd*(dd+1)*(2*dd+1)/3!=ssum[r]-ssum[l-1]){
cout<<"No"<<endl;
continue;
}
if ((__int128)dd*dd*(dd+1)*(dd+1)/2!=sssum[r]-sssum[l-1]){
cout<<"No"<<endl;
continue;
}
cout<<"Yes"<<endl;
}
}
}
哈希做法,一段区间构成双排列的必要条件是:
维护区间的前缀和可以判断是否满足哈希函数,哈希函数发生冲突的概率与区间的大小成负相关
所以可以采取分治的方式将 \(n\le500\) 的数据进行暴力计算,较大的区间利用哈希值检验是否正确
这样发生哈希冲突的概率极低,可以视作充分必要条件