8.8~8.13考试总结
8.9
wave
【题目描述】
海浪分为前浪和后浪,分别用数字 0 和数字 1 表示。 现在给定一天中 n 个时段的海浪序列,第 i 个序列包含 $m_i$ 个海浪。 全天海浪序列是 n 个时段的海浪序列按照任意的一种次序顺次拼接而成的序列。 一个涨潮定义为海浪序列的一个子序列(不必连续),满足这个子序列中的任何一个前浪 都出现在任何一个后浪之前。涨潮的强度定义为其中包含的海浪个数。 请你求出所有可能的全天海浪序列中,强度最大的涨潮的强度最大值。【输入格式】
从文件 wave.in 中读入数据。 第一行一个正整数 n,表示序列个数。 接下来 n 行,第 i + 1 行一个正整数 $m_i$,其后紧随 $m_i$ 个数字 0 或 1,描述了一个海浪 序列。【输出格式】
输出到文件 wave.out 中。 第一行一个正整数,表示强度最大的涨潮的强度。\(solution\)
考虑每一个海浪序列全是1或者全是0所提供的最大贡献,与这个序列在中间的最大涨潮度相比较,保证所有序列的贡献加起来最大
AC Code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int N=5e5+5;
int n,sum[N],s[N],sum1[N],ans=0;
int m0[N],m1[N],sum2[N];
int main()
{
// freopen("wave.in","r",stdin);
// freopen("wave.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
{
sum[i]=read();sum[i]+=sum[i-1];
for(int j=sum[i-1]+1;j<=sum[i];j++)
{
s[j]=read();
if(s[j]==0)m0[j]=m0[j-1]+1,m1[j]=m1[j-1];
else m1[j]=m1[j-1]+1,m0[j]=m0[j-1];
}
sum1[i]=max(m0[sum[i]]-m0[sum[i-1]],m1[sum[i]]-m1[sum[i-1]]);
sum2[i]=sum2[i-1]+sum1[i];
int tmp=0;
ans=max(ans,m0[sum[i]]-m0[sum[i-1]]-sum1[i]);
for(int j=sum[i];j>sum[i-1];j--)
{
if(s[j]==1)tmp++;
ans=max(ans,tmp+m0[j-1]-m0[sum[i-1]]-sum1[i]);
}
}
printf("%d\n",ans+sum2[n]);
return 0;
}
scientist
\(solution\)
50pts:
枚举通知的据点 T,那么第 i 个据点的人会在 \(f_{T (i)} = a_i + |T − i|\) 分钟结束时到达道路上。所以当j > fT (j)时,送货的人会被挡住。
又因为送货的人可能在被挡住之前,他的左右两侧都有人,所以目标达成的时间为:
\[max(min_{1\leq i < j}{f_{T(i)}},min_{j\leq i \leq n}{f_{T(i)}})
\]
rain
8.10
Cytoid
\(solution\)
直接暴力,可惜考场上太谨慎,没把暴力打好
开两个前缀和矩阵,分别记录x和?,然后枚举以点(i,j)为左上角的矩形,看是否可行
AC Code
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
const int mod = 998244353;
int n, m, f[N][N];
int a[N][N],b[N][N];
char s;
int qow(long long x,int y)
{
long long res=1;
while(y>0)
{
if(y&1)res*=x,res%=mod;
x*=x;x%=mod;y>>=1;
}
return res%mod;
}
int check(int x, int y)
{
int res=0;
for(int i=x;i<=n;i++)
{
for(int j=y;j<=m;j++)
{
int tmp1=a[i][j]-a[x-1][j]-a[i][y-1]+a[x-1][y-1];
if(tmp1!=0)continue;
int tmp2=b[i][j]-b[x-1][j]-b[i][y-1]+b[x-1][y-1];
if(tmp2==0)res+=1;
else res+=1*qow(2,mod-tmp2-1);
res%=mod;
}
}
return res;
}
int main()
{
// freopen("cai.in","r",stdin);
// freopen("cai.out","w",stdout);
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>s;
if(s=='x')a[i][j]=1;
if(s=='?')b[i][j]=1;
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int tmp=check(i,j);
ans+=tmp;
ans%=mod;
}
}
printf("%d\n",ans);
return 0;
}
串
\(solution\)
AC自动机+链并(计算贡献)
灯
\(solution\)
用分块/线段树来处理区间查询和区间修改就好了
AC Code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=x*10+int(ch-'0');
ch=getchar();
}
return x*f;
}
const int N=25e4+10;
int n,m;
string str;
struct ww{
int l,r,len,tag;
int sum,num[11];
}tr[N<<3];
void pushup(int p)
{
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
for(int i=0;i<10;++i)
tr[p].num[i]=tr[p<<1].num[i]+tr[p<<1|1].num[i];
return ;
}
void build(int p,int l,int r)
{
tr[p].l=l,tr[p].r=r;
tr[p].len=r-l+1;
tr[p].tag=0;
if(l==r)
{
tr[p].sum=int(str[l-1]-'0');
++tr[p].num[tr[p].sum];
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
return ;
}
void add(int p,int x)
{
if(!x) return ;
x%=10;
int lsum=0;
for(int i=10-x;i<10;++i)
lsum+=tr[p].num[i];
tr[p].sum+=x*tr[p].len-lsum*10;
int a[10];
for(int i=0;i<10;++i)
a[i]=tr[p].num[i];
for(int i=0;i<10;++i)
tr[p].num[(i+x)%10]=a[i];
return ;
}
void pushdown(int p)
{
tr[p].tag%=10;
if(tr[p].tag)
{
add(p<<1,tr[p].tag);
add(p<<1|1,tr[p].tag);
tr[p<<1].tag+=tr[p].tag;
tr[p<<1|1].tag+=tr[p].tag;
tr[p].tag=0;
}
return ;
}
void change(int p,int l,int r)
{
int l1=tr[p].l,r1=tr[p].r;
if(l<=l1 && r1<=r)
{
add(p,1);
(tr[p].tag+=1)%=10;
return ;
}
pushdown(p);
int mid=(l1+r1)>>1;
if(l<=mid) change(p<<1,l,r);
if(mid<r) change(p<<1|1,l,r);
pushup(p);
return ;
}
int ask(int p,int l,int r)
{
int l1=tr[p].l,r1=tr[p].r;
if(l<=l1 && r1<=r)
{
return tr[p].sum;
}
pushdown(p);
int cnt=0;
int mid=(l1+r1)>>1;
if(l<=mid) cnt+=ask(p<<1,l,r);
if(mid<r) cnt+=ask(p<<1|1,l,r);
pushup(p);
return cnt;
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
n=read(),m=read();
cin>>str;
int l,r;
build(1,1,n);
while(m--)
{
l=read(),r=read();
printf("%d\n",ask(1,l,r));
change(1,l,r);
}
return 0;
}
8.13
冒泡排序(sort)
\(solution\)
30pts:可知需要求的轮数等于\(max_{i=1}^{n}{i-r_i}\),即原位置与大小排序的位置的最大差值
100pts:用值域线段树在区间[l,r]中记录\(max_{i=l}^{r}{p_i-\sum_{j=l}^{i}{s_j}}\)与\(\sum_{i=l}^{r}{s_i}\),其中\(p_i\)表示i在序列中最后一次出现的位置,\(s_i\)表示i在序列中出现的次数
AC Code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int N=5e5+5;
int a[N];
set<int>s[N];
int tr[N*4],sum[N*4];
void updat(int p)
{
sum[p]=sum[p<<1]+sum[p<<1|1];
tr[p]=max(tr[p<<1],tr[p<<1|1]-sum[p<<1]);
}
void add(int p,int l,int r,int x)
{
if(l==r&&l==x)
{
sum[p]=s[x].size();
if(sum[p])tr[p]=*s[x].rbegin()-sum[p];
else tr[p]=0;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)add(p<<1,l,mid,x);
else add(p<<1|1,mid+1,r,x);
updat(p);
}
int main()
{
int n=read(),q=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
s[a[i]].insert(i);
add(1,1,N,a[i]);
}
int x,y;
for(int i=1;i<=q;i++)
{
x=read(),y=read();
s[a[x]].erase(x);
add(1,1,N,a[x]);
a[x]=y;
s[a[x]].insert(x);
add(1,1,N,a[x]);
cout<<tr[1]<<endl;
}
return 0;
}

浙公网安备 33010602011771号