牛客挑战赛55
比赛
A
肯定从小到大构造,不难发现最大序列就是斐波那契数列
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long
using namespace std;
const int maxn=1000001+101;
const int MOD=100007;
const int inf=2147483647;
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
ll n,f[maxn];
int main(){
n=read();
f[1]=1;f[2]=1;int i;
for(i=3;;){
if(f[i-1]+f[i-2]>n){i--;break;}
f[i]=f[i-1]+f[i-2];i++;
}
cout<<i<<endl;
for(int j=1;j<=i;j++)cout<<f[j]<<" ";
return 0;
}
B
显然k不会超过\(log(10^9)\),每层进行哈希,记录相同余数的个数
枚举k从小到大,把相同余数个数相加即可
正确性证明:
假设当前k=1,\(a_x=c^1\cdot c^{x_1} \cdot t_1+b_1,a_y=c^1\cdot c^{x_2} \cdot t_2+b_1\)余数相等,
这连续的\(k=1,2,···,1+min(x_1,x_2)\)余数都相同,ans在每层都会加1,加了\(min(x_2,x_1)+1\)层,正好加了\(max\{k|a_x\equiv a_y(mod c^k)\}\)
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<map>
#define ll long long
using namespace std;
const int maxn=1000001+101;
const int MOD=100007;
const int inf=2147483647;
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,c,a[maxn];
int main(){
n=read();c=read();
for(int i=1;i<=n;i++)a[i]=read();
ll ans=0,ji=c;
while(ji<=1000000000){
map<int,ll>q;
for(int i=1;i<=n;i++)ans+=(q[a[i]%ji]++);
ji*=(ll)c;
}
printf("%lld",ans<<1);
return 0;
}
C
此题求a[i][j]的乘积最大,换句话就是一个矩形内的\(log_2(a[i][j])\)相加最大
所以尽可能找尽量大的矩形,并算出矩形内的和,并对所有矩形的和取最大值
le,ri用来表示(i,j)如果跟i-1行以上形成最大矩形的最大左右界
i-up[i][j]+1用来表示(i,j)跟i-1行以上形成最大矩形的上界
对每个点进行上述操作,则可以求得所有矩形的和以及最大值
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<map>
#define ll long long
using namespace std;
const int maxn=1000+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
ll power(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans=ans*x%MOD;
y>>=1;x=x*x%MOD;
}
return ans;
}
int n,m,a[maxn][maxn],up[maxn][maxn],le[maxn][maxn],ri[maxn][maxn],sum[maxn][maxn];
int calc(int a,int b,int c,int d){return sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1];}
int main(){
n=read();m=read();
int ans=-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
if(a[i][j]==0)a[i][j]=-1;
else a[i][j]=log(a[i][j])/log(2);
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
memset(le,0,sizeof(le));
memset(ri,63,sizeof(ri));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==-1)up[i][j]=0;
else up[i][j]=up[i-1][j]+1;
}
int lst=0;
for(int j=1;j<=m;j++){
if(a[i][j]==-1)lst=j;
else le[i][j]=max(lst+1,le[i-1][j]);
}
lst=m+1;
for(int j=m;j>=1;j--){
if(a[i][j]==-1)lst=j;
else{
ri[i][j]=min(lst-1,ri[i-1][j]);
ans=max(ans,calc(i-up[i][j]+1,le[i][j],i,ri[i][j]));
}
}
}
if(ans==-1)puts("0");
else printf("%lld\n",power(2,ans));
return 0;
}
D
发现函数嵌套后关于x还是一个函数而且是一次函数ax+b。这个自己推一下易证。
于是就可以线段树维护单点修改和区间查询了。
对与函数嵌套的与x有关的系数a维护很简单,主要是b的区间修改不好pushdown
考虑区间加后对合并后函数的变化。
k 值显然不变,b值可以考虑每个函数被加x的贡献,来尝试维护b的变化量。
假设区间[l,r]的b值加x
\(b_l导致的变化量为x\cdot k_{l+1}\cdot k_{l+2}····\)
\(b_{l+1}导致的变化量为x\cdot k_{l+2}\cdot k_{l+3}····\)
所以对于区间[l,r]的b的变化量为
\(x+x\cdot\sum_{i=l}^{r-1} \prod_{j=i+1}^r k_j\)
x修改时,只要维护\(1+\sum_{i=l}^{r-1} \prod_{j=i+1}^r k_j\)就行
下述代码中
对于tr[k]所代表的区间:
a代表系数积,c表示当前区间函数嵌套的与x无关的和,b就是所维护的\(1+\sum_{i=l}^{r-1} \prod_{j=i+1}^r k_j\)
则\(tr[k].b=tr[k<<1].b*tr[k<<1|1].a+tr[k<<1|1].b\)(可以把b所代表的式子分成两半即可发现结论)
另外重载运算符讲解
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<map>
#define ll long long
using namespace std;
const int maxn=2e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,m,k0[maxn],b[maxn],lz[maxn];
struct wzq{
ll a,b,c;
wzq operator+(wzq x){
return (wzq){x.a*a%MOD,(x.a*b+x.b)%MOD,(x.a*c+x.c)%MOD};
}
}tr[maxn];
void up(int k){tr[k]=tr[k<<1]+tr[k<<1|1];return ;}
void build(int k,int l,int r){
if(l==r){
tr[k]=(wzq){k0[l],1,b[l]};
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
up(k);return ;
}
void add(int k,ll v){
(tr[k].c+=tr[k].b*v)%=MOD;
(lz[k]+=v)%=MOD;
}
void update(int k,int l,int r,int L,int R,int tag,ll val){
if(r<L || l>R)return ;
if(L<=l && r<=R){
if(tag==1)tr[k].a=val;
else add(k,val);
return ;
}
if(lz[k]){
add(k<<1,lz[k]);
add(k<<1|1,lz[k]);
lz[k]=0;
}
int mid=(l+r)>>1;
update(k<<1,l,mid,L,R,tag,val);update(k<<1|1,mid+1,r,L,R,tag,val);
up(k);return ;
}
void query(int k,int l,int r,int L,int R,ll &x){
if(r<L || l>R)return ;
if(L<=l && r<=R){x=(tr[k].a*x+tr[k].c)%MOD;return ;}
if(lz[k]){
add(k<<1,lz[k]);
add(k<<1|1,lz[k]);
lz[k]=0;
}
int mid=(l+r)>>1;
query(k<<1,l,mid,L,R,x);query(k<<1|1,mid+1,r,L,R,x);
up(k);return;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)k0[i]=read();
for(int i=1;i<=n;i++)b[i]=read();
build(1,1,n);
while(m--){
int opt=read();
if(opt==1){
int x=read(),kk=read();
update(1,1,n,x,x,1,kk);
}
else if(opt==2){
int l=read(),r=read(),v=read();
update(1,1,n,l,r,2,v);
}
else {
int l=read(),r=read();ll x=read();
query(1,1,n,l,r,x);
printf("%lld\n",x);
}
}
return 0;
}