九下三月中旬日记

3.11

闲话

  • @wkh2008@lty_ylzsx\(miaomiao\)\(1\) 机房赶到 \(3\) 机房了。
  • 不知道为啥 \(field\) 来催了下改模拟赛的题,可能为了缓解尴尬(?)。

做题纪要

tgHZOJ 2893. 混乱邪恶

luogu P1412 经营与开发

  • 发现顺序枚举存在后效性,考虑倒序枚举。

  • \(f_{i}\) 表示截止到第 \(i\) 个星球时 \(1\) 能力值能获得的最大金钱,状态转移方程为 \(f_{i}= \begin{cases} \max(f_{i+1},(1-0.01k)f_{i+1}+x_{i}) & type_{i}=1 \\ \max(f_{i+1},(1+0.01c)f_{i+1}-x_{i}) & type_{i}=2 \end{cases}\)

    点击查看代码
    int pd[200000];
    double x[200000],f[200000];
    int main()
    {
    	int n,i;
    	double k,c,w;
    	cin>>n>>k>>c>>w;
    	for(i=1;i<=n;i++)
    	{
    		cin>>pd[i]>>x[i];
    	}
    	for(i=n;i>=1;i--)
    	{
    		f[i]=max(f[i+1],(pd[i]==1)?f[i+1]*(1-0.01*k)+x[i]:f[i+1]*(1+0.01*c)-x[i]);
    	}
    	printf("%.2lf\n",f[1]*w);
    	return 0;
    }
    

3.12

闲话

  • 貌似调考成绩算回原班级,已经在想象调考后以前课任老师上来 \(D\) 人了。

做题纪要

[ABC343G] Compress Strings

  • 多倍经验: CF25E Test

  • 由于 \(\sum\limits_{i=1}^{n} |S_{i}|\) 极大且不需要记录路径,所以 luogu P2322 [HNOI2006] 最短母串问题 的枚举所有可能的字符串 \(T\) 进行判断不可做。

  • \(f_{i,j}\) 表示当“字符串包含状态”对应的二进制数为 \(i\) 时,且结尾为 \(j\) 时的最小长度,状态转移方程为 \(f_{i,j}= \min\limits_{j \ne k,(i \gg k) \And 1 \ne 0}^{} \{f_{i-(1 \ll j),k}-g_{k,j}+|S_{j}| \}\) ,其中 \(g_{k,j}\) 表示 \(S_{k}\) 的后缀和 \(S_{j}\) 的前缀匹配的最长长度,使用 \(KMP\) 维护即可。

  • 注意去重和删去在其他字符串中已被包含的字符串。

    点击查看代码
    int nxt[200010],f[(1<<22)+10][22],g[22][22];
    string s[22],ss[22],t;
    int main()
    {
    	int m,n=0,ans=0x7f7f7f7f,flag,i,j,k,x,y;
    	cin>>m;
    	memset(f,0x3f,sizeof(f));
    	for(i=0;i<=m-1;i++)
    	{
    		cin>>ss[i];
    	}
    	sort(ss+0,ss+m);
    	m=unique(ss+0,ss+m)-ss;
    	for(i=0;i<=m-1;i++)
    	{
    		flag=0;
    		for(j=0;j<=m-1;j++)
    		{
    			if(i!=j&&ss[j].find(ss[i])!=string::npos)
    			{
    				flag=1;
    				break;
    			}
    		}
    		if(flag==0)
    		{
    			s[n]=ss[i];
    			n++;
    		}
    	}
    	for(x=0;x<=n-1;x++)
    	{
    		for(y=0;y<=n-1;y++)
    		{
    			if(x!=y)
    			{
    				t=' '+s[y]+'#'+s[x];
    				for(i=2,nxt[1]=j=0;i<t.size();i++)
    				{
    					while(j>=1&&t[i]!=t[j+1])
    					{
    						j=nxt[j];
    					}
    					j+=(t[i]==t[j+1]);
    					nxt[i]=j;
    				}
    				g[x][y]=nxt[t.size()-1];
    			}
    		}
    	}
    	for(i=0;i<=n-1;i++)
    	{
    		f[(1<<i)][i]=s[i].size();
    	}
    	for(i=0;i<=(1<<n)-1;i++)
    	{
    		for(j=0;j<=n-1;j++)
    		{
    			if((i>>j)&1)
    			{
    				for(k=0;k<=n-1;k++)
    				{
    					if(j!=k&&((i>>k)&1))
    					{
    						f[i][j]=min(f[i][j],f[i-(1<<j)][k]-g[k][j]+(int)s[j].size());
    					}
    				}
    			}
    		}
    	}
    	for(i=0;i<=n-1;i++)
    	{
    		ans=min(ans,f[(1<<n)-1][i]);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

3.13

闲话

  • 下午到机房的时候,发现电脑在今天上午 \(11:30\) 的时候死机了,浏览记录多了个 tgHZOJ 。
  • 因和 \(miaomiao\) 交涉失败,下午要去博艺馆开中考百日誓师大会,占了下午第 \(8,9\) 节课。因有家长和老师参与,故 \(25,26,27\) 班只能坐在过道。洗脑痕迹明显。
  • 开完大会说让回班让班主任开百日誓师班会,但现班主任出差了,代班主任连上周日的班会都没开,索性直接来机房了。
  • 晚上回班后发现应该开班会的课改成公自了,赌赢了。

做题纪要

luogu P3214 [HNOI2011] 卡农

  • 简化题意

    • 给定 \(n,m\) 。求在集合 \(S= \{ 1,2,3, \dots ,n \}\) 中选出 \(m\) 个子集,且这 \(m\) 个子集满足以下三个性质的无序集合方案数。
      • 性质 \(1\) :选出的 \(m\) 个子集中每个子集都不能为空。
      • 性质 \(2\) :选出的 \(m\) 个子集中不存在两个相同的子集。
      • 性质 \(3\) :选出的 \(m\) 个子集中 \(1 \sim n\) 的每个数的总出现次数必须是偶数。
  • \(f_{i}\) 表示到当前枚举到第 \(i\) 个子集时,满足三个性质的有序集合方案数,状态转移方程为 \(f_{i}= \begin{cases} 1 & i=0 \\ A_{2^{n}-1}^{i-1}-f_{i-1}-f_{i-2} \times A_{i-1}^{1} \times A_{2^{n}-1-(i-2)}^{1} & i \ne 0 \end{cases}\)

    • 假设当前已确认了前 \(i-1\) 个子集,且前 \(i-1\) 个子集满足三个性质。
    • 加上第 \(i\) 个子集后满足性质 \(3\) 的共有 \(A_{2^{n}-1}^{i-1}\) 种方案。
      • 从二进制下异或和的角度分析,该结论显然。
    • 加上第 \(i\) 个子集后满足性质 \(3\) ,但不满足性质 \(1\) ,即第 \(i\) 个子集为空的共有 \(f_{i-1}\) 种方案。
    • 加上第 \(i\) 个子集后满足性质 \(3\) ,但不满足性质 \(2\) ,即第 \(i\) 个子集在前 \(i-1\) 个子集中已经出现过一次的共有 \(f_{i-2} \times A_{i-1}^{1} \times A_{2^{n}-1-(i-2)}^{1}\) 种方案。
  • \(A_{n}^{m} \times \frac{1}{n-m+1}=A_{n}^{m-1}\) ,有 \(A_{n}^{m}=A_{n}^{m-1} \times (n-m+1)\)

  • 最终,有 \(\frac{f_{m}}{A_{m}^{m}}\) 即为所求。

    点击查看代码
    const ll p=100000007;
    ll inv[1000010],jc[1000010],jc_inv[1000010],a[1000010],f[1000010];
    void A1(ll n,ll m,ll p)
    {
    	a[0]=1;
    	for(ll i=1;i<=m;i++)
    	{
    		a[i]=a[i-1]*(n-i+1)%p;
    	}
    }
    ll A2(ll n,ll m,ll p)
    {   
    	return (n>=m&&n>=0&&m>=0)?((m==1)?n:jc[n]*jc_inv[n-m]%p):0;
    }
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b>0)
    	{
    		if(b&1)
    		{
    			ans=ans*a%p;
    		}
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    int main()
    {
    	ll n,m,sum,i;
    	cin>>n>>m;
    	sum=(qpow(2,n,p)-1+p)%p;
    	A1(sum,m,p);
    	inv[1]=1;
    	jc[0]=jc_inv[0]=jc[1]=jc_inv[1]=1;
    	for(i=2;i<=max(n,m);i++)
    	{
    		inv[i]=(p-p/i)*inv[p%i]%p;
    		jc[i]=jc[i-1]*i%p;
    		jc_inv[i]=jc_inv[i-1]*inv[i]%p;
    	}
    	f[0]=1;
    	for(i=1;i<=m;i++)
    	{
    		f[i]=((a[i-1]-f[i-1]+p)%p-(f[i-2]*A2(i-1,1,p)%p)*A2(sum-(i-2),1,p)%p+p)%p;
    	}
    	cout<<f[m]*qpow(A2(m,m,p),p-2,p)%p<<endl;
    	return 0;
    }
    

luogu P4884 多少个 1?

  • \(\begin{matrix}n 个 1 \\ \overbrace{11 \dots 1}\end{matrix} \equiv b \pmod{p}\) 等价于 \(\frac{10^{n}-1}{9} \equiv b \pmod{p}\) ,移项得 \(10^{n} \equiv (9b+1) \pmod{p}\)

    点击查看代码
    #define ll __int128_t
    ll read()
    {
    	ll x=0,f=1;
    	char c=getchar();
    	while(c>'9'||c<'0')
    	{
    		if(c=='-')
    		{
    			f=-1;
    		}
    		c=getchar();
    	}
    	while('0'<=c&&c<='9')
    	{
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    void write(ll x)
    {
    	if(x<0)
    	{
    		putchar('-');
    		x=-x;
    	}
    	if(x>9)
    	{
    		write(x/10);
    	}
    	putchar((x%10)+'0');
    }
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b>0)
    	{
    		if(b&1)
    		{
    			ans=ans*a%p;
    		}
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    ll bsgs(ll a,ll b,ll p)
    {
    	if(1%p==b%p)
    	{
    		return 0;
    	}
    	else
    	{
    		map<ll,ll>vis;
    		ll k=sqrtl(p)+1,i,sum;
    		for(i=0;i<=k-1;i++)
    		{
    			vis[b*qpow(a,i,p)%p]=i;
    		}
    		a=qpow(a,k,p);
    		for(i=0;i<=k;i++)
    		{
    			sum=qpow(a,i,p);
    			if(vis.find(sum)!=vis.end())
    			{
    				if(i*k-vis[sum]>=0)
    				{
    					return i*k-vis[sum];
    				}
    			}
    		}
    		return -1;
    	}
    }
    int main()
    {
    	ll b,p;
    	b=read();
    	p=read();
    	write(bsgs(10,9*b+1,p));
    	return 0;
    }
    

luogu P4454 [CQOI2018] 破解D-H协议

  • 原根 定义,有 \(\gcd(g,p)=1\)

    点击查看代码
    #define ll __int128_t
    ll read()
    {
    	ll x=0,f=1;
    	char c=getchar();
    	while(c>'9'||c<'0')
    	{
    		if(c=='-')
    		{
    			f=-1;
    		}
    		c=getchar();
    	}
    	while('0'<=c&&c<='9')
    	{
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    void write(ll x)
    {
    	if(x<0)
    	{
    		putchar('-');
    		x=-x;
    	}
    	if(x>9)
    	{
    		write(x/10);
    	}
    	putchar((x%10)+'0');
    }
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b>0)
    	{
    		if(b&1)
    		{
    			ans=ans*a%p;
    		}
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    ll bsgs(ll a,ll b,ll p)
    {
    	if(1%p==b%p)
    	{
    		return 0;
    	}
    	else
    	{
    		map<ll,ll>vis;
    		ll k=sqrtl(p)+1,i,sum;
    		for(i=0;i<=k-1;i++)
    		{
    			vis[b*qpow(a,i,p)%p]=i;
    		}
    		a=qpow(a,k,p);
    		for(i=0;i<=k;i++)
    		{
    			sum=qpow(a,i,p);
    			if(vis.find(sum)!=vis.end())
    			{
    				if(i*k-vis[sum]>=0)
    				{
    					return i*k-vis[sum];
    				}
    			}
    		}
    		return -1;
    	}
    }
    int main()
    {
    	ll g,p,n,a,b,i;
    	g=read();
    	p=read();
    	n=read();
    	for(i=1;i<=n;i++)
    	{
    		a=read();
    		b=read();
    		write(qpow(a,bsgs(g,b,p),p));
    		cout<<endl;
    	}
    	return 0;
    }
    

3.14

闲话

  • 早上到机房的时候,发现电脑在今天凌晨 \(2:10\) 的时候死机了,以后走的时候索性直接关机了。
  • 回班的时候看见 \(miaomiao\) 坐在靠门的位置摆弄 \(NOI \ Linux \ 2.0\) ,但他为什么不坐在教师机的位置呢。
  • \(miaomiao\) 下午 \(14:00 \sim 18:05\) 安排了一场模拟赛,可能以后都是周四有模拟赛。
  • 下午 \(14:06\) 的时候 @jijidawang 才到机房,然后被 \(miaomiao\) \(D\) 了。
  • 晚上代班主任说周五第一节课调到下午上,成功少了一节仅有 \(40min\) 的奥赛课。

做题纪要

luogu P5025 [SNOI2017] 炸弹

  • \([L_{i},R_{i}]\) 表示第 \(i\) 颗炸弹所能引爆的炸弹区间。

  • 处理出第 \(i\) 颗炸弹的实际引爆半径 \(r_{i}'\) ,然后分别对左右端点进行转移即可。

    点击查看代码
    const ll p=1000000007;
    ll x[500010],r[500010],L[500010],R[500010];
    int main()
    {
    	ll n,ans=0,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>x[i]>>r[i];
    		L[i]=R[i]=i;
    	}
    	for(i=1;i<=n;i++)
    	{
    		while(L[i]-1>=1&&x[i]-r[i]<=x[L[i]-1])
    		{
    			r[i]=max(r[i],x[L[i]-1]+r[L[i]-1]-x[i]);
    			L[i]=L[L[i]-1];
    		}
    	}
    	for(i=n;i>=1;i--)
    	{
    		while(R[i]+1<=n&&x[i]+r[i]>=x[R[i]+1])
    		{
    			L[i]=min(L[i],L[R[i]+1]);//可能存在先炸右边得到的左端点比先炸左边得到的左端点更靠左
    			R[i]=R[R[i]+1];
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		ans=(ans+(R[i]-L[i]+1)*i%p)%p;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

CF56E Domino Principle

  • 将多米诺骨牌压倒转化为炸弹爆炸即可,注意只更新右端点。

    点击查看代码
    struct node
    {
    	int x,r,L,R,id;
    }a[100010];
    bool cmp1(node a,node b)
    {
    	return a.x<b.x;
    }
    bool cmp2(node a,node b)
    {
    	return a.id<b.id;
    }
    int main()
    {
    	int n,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i].x>>a[i].r;
    		a[i].r--;
    		a[i].id=i;
    	}
    	sort(a+1,a+1+n,cmp1);
    	for(i=1;i<=n;i++)
    	{
    		a[i].L=a[i].R=i;
    	}
    	for(i=n;i>=1;i--)
    	{
    		while(a[i].R+1<=n&&a[i].x+a[i].r>=a[a[i].R+1].x)
    		{
    			a[i].r=max(a[i].r,a[a[i].R+1].x+a[a[i].R+1].r-a[i].x);
    			a[i].R=a[a[i].R+1].R;
    		}
    	}
    	for(i=n;i>=1;i--)
    	{
    		while(a[i].R+1<=n&&a[i].x+a[i].r>=a[a[i].R+1].x)
    		{
    			a[i].R=max(a[i].R,a[a[i].R+1].R);
    		}
    	}
    	sort(a+1,a+1+n,cmp2);
    	for(i=1;i<=n;i++)
    	{
    		cout<<a[i].R-a[i].L+1<<" ";
    	}
    	return 0;
    }
    

LibreOJ 6277. 数列分块入门 1

  • 维护整块的增量标记 \(add_{i}\) 即可。

  • 块长取 \(\sqrt{n}\)

    点击查看代码
    ll a[50010],add[50010],L[50010],R[50010],pos[50010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=min(R[i-1]+klen,n);
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    void update(ll l,ll r,ll val)
    {
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]+=val;
    		}
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			add[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]+=val;
    		}
    	}
    }
    ll ask(ll l)
    {
    	return a[l]+add[pos[l]];
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    	}
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update(l,r,val);
    		}
    		else
    		{
    			printf("%lld\n",ask(r));
    		}
    	}
    	return 0;
    }
    

HDU1166 敌兵布阵

  • 块长取 \(\sqrt{n}\)

    点击查看代码
    int a[50010],sum[50010],L[50010],R[50010],pos[50010],klen,ksum;
    void init(int n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)
    	{
    		sum[i]=0;
    		for(int j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    			sum[i]+=a[j];
    		}
    	}
    }
    void update(int l,int val)
    {
    	a[l]+=val;
    	sum[pos[l]]+=val;
    }
    int query(int l,int r)
    {
    	int ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(int i=l;i<=r;i++)
    		{
    			ans+=a[i];
    		}
    	}
    	else
    	{
    		for(int i=l;i<=R[pos[l]];i++)
    		{
    			ans+=a[i];
    		}
    		for(int i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans+=sum[i];
    		}
    		for(int i=L[pos[r]];i<=r;i++)
    		{
    			ans+=a[i];
    		}
    	}
    	return ans;
    }
    int main()
    {
    	int t,n,l,r,i,j;
    	char pd[10];
    	scanf("%d",&t);
    	for(j=1;j<=t;j++)
    	{
    		scanf("%d",&n);
    		for(i=1;i<=n;i++)
    		{
    			scanf("%d",&a[i]);
    		}
    		init(n);
    		printf("Case %d:\n",j);
    		while(scanf("%s",pd+1))
    		{
    			if(pd[1]=='E')
    			{
    				break;
    			}
    			scanf("%d%d",&l,&r);
    			if(pd[1]=='A')
    			{
    				update(l,r);
    			}
    			if(pd[1]=='S')
    			{
    				update(l,-r);
    			}
    			if(pd[1]=='Q')
    			{
    				printf("%d\n",query(l,r));
    			}
    		}
    	}
    	return 0;
    }
    

LibreOJ 6280. 数列分块入门 4

  • 维护整块的增量标记 \(add_{i}\) 即可。

  • 块长取 \(\sqrt{n}\)

    点击查看代码
    ll a[50010],sum[50010],add[50010],L[50010],R[50010],pos[50010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    			sum[i]+=a[j];
    		}
    	}
    }
    void update(ll l,ll r,ll val)
    {
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		sum[pos[l]]+=val*(r-l+1);
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]+=val;
    		}
    		sum[pos[l]]+=val*(R[pos[l]]-l+1);
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			add[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		sum[pos[r]]+=val*(r-L[pos[r]]+1);
    	}
    }
    ll query(ll l,ll r,ll p)
    {       
    	ll ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			ans=(ans+a[i]%p)%p;
    		}
    		ans=(ans+(add[pos[l]]%p)*(r-l+1)%p)%p;
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			ans=(ans+a[i]%p)%p;
    		}
    		ans=(ans+(add[pos[l]]%p)*(R[pos[l]]-l+1)%p)%p;
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans=((ans+sum[i]%p)%p+(add[i]%p)*(klen%p)%p)%p;
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			ans=(ans+a[i]%p)%p;
    		}
    		ans=(ans+(add[pos[r]]%p)*(r-L[pos[r]]+1)%p)%p;
    	}
    	return ans;
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    	}
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update(l,r,val);
    		}
    		else
    		{
    			printf("%lld\n",query(l,r,val+1));
    		}
    	}
    	return 0;
    }
    

UVA12003 Array Transformer

  • 多倍经验:SP3261 RACETIME - Race Against Time | SP18185 GIVEAWAY - Give Away

  • 对于在整块内找小于给出的数的所有元素个数,容易想到对块内元素进行排序,然后二分查找得到答案。

    点击查看代码
    ll a[50010],b[50010],L[50010],R[50010],pos[50010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    		sort(b+L[i],b+R[i]+1);
    	}
    }
    void update(ll l,ll val)
    {
    	b[lower_bound(b+L[pos[l]],b+R[pos[l]]+1,a[l])-b]=val;
    	a[l]=val;
    	sort(b+L[pos[l]],b+R[pos[l]]+1);
    }
    ll query(ll l,ll r,ll val)
    {
    	ll ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			ans+=(a[i]<=val);
    		}
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			ans+=(a[i]<=val);
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans+=lower_bound(b+L[i],b+R[i]+1,val)-b-L[i];
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			ans+=(a[i]<=val);
    		}
    	}
    	return ans;
    }
    int main()
    {
    	ll n,m,u,l,r,val,p,i;
    	char pd;
    	cin>>n>>m>>u;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		b[i]=a[i];
    	}
    	init(n);
    	for(i=1;i<=m;i++)
    	{
    		cin>>l>>r>>val>>p;
    		update(p,u*query(l,r,val)/(r-l+1));
    	}
    	for(i=1;i<=n;i++)
    	{
    		cout<<a[i]<<endl;
    	}
    	return 0;
    }
    

3.15

闲话

  • @wkh2008\(miaomiao\) 叫到机房学高一 \(whk\) 了。
  • 吃完早饭 @Vsinger_洛天依 给我说 \(miaomiao\) 问他报不报 \(APIO\) ,他说报,然后 \(miaomiao\) 就把他报上去了,但 \(miaomiao\) 根本没和我们说这件事。
  • 吃完晚饭后看见 \(field\) 领着 \(4,5\) 个 ZZ (女生居多)的在校园里面转,不知道是来干什么的。
  • 晚上年级部说要改作息,早上从 \(6:50\) 起床改到了 \(6:20\) 起床了,多出来的 \(30min\) 分成了 \(20min\) 的早读和 \(10min\) 的课间(但实际上被早读占了)。

做题纪要

LibreOJ 6278. 数列分块入门 2

  • 多倍经验: luogu P2801 教主的魔法

  • 对于整块的修改操作,其相对大小顺序不变,故维护整块的增量标记 \(add_{i}\) 即可。

    点击查看代码
    ll a[50010],b[50010],add[50010],L[50010],R[50010],pos[50010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    		sort(b+L[i],b+R[i]+1);
    	}
    }
    void update(ll l,ll r,ll val)
    {
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)//因是区间修改,所以直接复制过来即可
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[l]],b+R[pos[l]]+1);
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[l]],b+R[pos[l]]+1);
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			add[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=R[pos[r]];i++)
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[r]],b+R[pos[r]]+1);
    	}
    }
    ll query(ll l,ll r,ll val)
    {
    	ll ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			ans+=(a[i]+add[pos[l]]<val);
    		}
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			ans+=(a[i]+add[pos[l]]<val);
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans+=lower_bound(b+L[i],b+R[i]+1,val-add[i])-b-L[i];
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			ans+=(a[i]+add[pos[r]]<val);
    		}
    	}
    	return ans;
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    		b[i]=a[i];
    	}
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update(l,r,val);
    		}
    		else
    		{
    			printf("%lld\n",query(l,r,val*val));
    		}
    	}
    	return 0;
    }
    

LibreOJ 6279. 数列分块入门 3

  • 注意在找整块时把增量标记 \(add\) 加回来。

    点击查看代码
    ll a[100010],b[100010],add[100010],L[100010],R[100010],pos[100010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    		sort(b+L[i],b+R[i]+1);
    	}
    }
    void update(ll l,ll r,ll val)
    {
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[l]],b+R[pos[l]]+1);
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[l]],b+R[pos[l]]+1);
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			add[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]+=val;
    		}
    		for(ll i=L[pos[r]];i<=R[pos[r]];i++)
    		{
    			b[i]=a[i];
    		}
    		sort(b+L[pos[r]],b+R[pos[r]]+1);
    	}
    }
    ll query(ll l,ll r,ll val)
    {
    	ll ans=-0x7f7f7f7f;
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			ans=max(ans,(a[i]+add[pos[l]]<val)?a[i]+add[pos[l]]:-0x7f7f7f7f);
    		}
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			ans=max(ans,(a[i]+add[pos[l]]<val)?a[i]+add[pos[l]]:-0x7f7f7f7f);
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans=max(ans,(lower_bound(b+L[i],b+R[i]+1,val-add[i])-b-1>=L[i])?b[lower_bound(b+L[i],b+R[i]+1,val-add[i])-b-1]+add[i]:-0x7f7f7f7f);
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			ans=max(ans,(a[i]+add[pos[r]]<val)?a[i]+add[pos[r]]:-0x7f7f7f7f);
    		}
    	}
    	return (ans==-0x7f7f7f7f)?-1:ans;
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    		b[i]=a[i];
    	}
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update(l,r,val);
    		}
    		else
    		{
    			printf("%lld\n",query(l,r,val));
    		}
    	}
    	return 0;
    }
    

CF1153D Serval and Rooted Tree

3.16

闲话

  • 上午第 \(5\) 节课课表写得是“公(A)”,然后 @lty_ylzsx 把“公()”擦了只剩下“A”,接着全班发出欢呼,我们就来机房了。
  • 下午 \(miaomiao\)\(3\) 机房电脑太差了,所以让我们搬到 \(4\) 机房了,顺便稍微收拾了下机房。 \(miaomiao\)\(D\) 了下高二的,说我们别把机房整得乱得跟高二的一样。我坐在了 @Trump_ 的位置上。
    • \(4\) 机房发现了数个乒乓球排、羽毛球排,还有一个篮球。
  • @jijidawang 请假回家了,但 \(miaoamiao\) 和我们不知道,误以为他消失了。
  • 下午高二的放假了。
  • \(4\) 机房有 \(3\) 台教师机, \(2\) 个键盘。貌似有一台能查是否有人改 \(IP\) 。接着高一改 \(IP\) 的事情就被教练发现了。
  • 下午从厕所回机房的路上看见年级德育主任从教练办公室出来了,不知道他来干啥。
  • 临吃饭的时候, \(miaomiao\) 称因为明天 luogu 有比赛,所以把我们明天下午旷周测的事情批了;接着我告诉 \(miaomiao\) 有 ABC ,然后他把我们晚上旷周测(一开始 \(miaomiao\) 以为我们非常热爱 \(whk\) ,所以是半节,后面 \(miaomiao\) 又反悔了 )的事情批了。
  • 晚上来机房后, \(feifei\) 问我们为啥今晚上来机房了,我们给他说晚上有 ABC ,结果 \(feifei\) 问我们啥是 ABC 。
  • 晚上 @wang54321@HS_xh 因在打 ABC 时交流,被 \(feifei\) \(D\) 了。

做题纪要

luogu P4550 收集邮票

LibreOJ 6089. 小 Y 的背包计数问题

[ABC345A] Leftrightarrow

[ABC345B] Integer Division Returns

[ABC345C] One Time Swap

3.17

闲话

  • 下午小孩哥在 \(3\) 机房听 \(miaomiao\) 讲高精度。
  • 下午高二的返校了。在机房看见了 @User_Unauthorized@Trump_ 来收拾书,他们貌似被发配到录播室补 whk 了。

做题纪要

luogu P10251 农场

luogu P10252 线性变换

tgHZOJ 2813. 起

3.18

闲话

做题纪要

3.19

  • 下午到机房的时候发现 \(4\) 机房把 luogu 封了,其他机房反而把 luogu 开了,成功进入 vjudge 改变生活 时期。

闲话

做题纪要

luogu P10253 说唱

CF922E Birds

CF1628D1 Game on Sum (Easy Version)

3.20

闲话

  • 下午到机房的时候,发现机房大部分电脑被重启了,我旁边的 \(Windows\)@wkh2008@K8He 的电脑幸免于难。
  • @K8He 请假回家了, @wkh2008 被迫回班学 \(whk\) 了。
  • 下午因我发出奇怪声音,被 \(miaomiao\) \(D\) 了。

做题纪要

2024年中国传媒大学程序设计大赛(同步赛)C 小红的 CUC

  • 直接构造即可。

    点击查看代码
    int main()
    {
    	int n,i;
    	cin>>n;
    	if(n>=3)
    	{
    		cout<<"CUC";
    		for(i=1;i<=n-3;i++)
    		{
    			cout<<"A";
    		}
    	}   
    	else
    	{
    		cout<<"-1"<<endl;
    	}
    	return 0;
    }
    

LibreOJ 6281. 数列分块入门 5

  • 多倍经验: luogu P4145 上帝造题的七分钟 2 / 花神游历各国 | SP2713 GSS4 - Can you answer these queries IV

  • 观察到 \(\left\lfloor \sqrt{a_{i}} \right\rfloor\) 的下降速度极快。

  • 类似 luogu P2898 [USACO08JAN] Haybale Guessing G 的思路。当 \(a_{i} \le 1\) 时,将第 \(i\) 棵树和第 \(i+1\) 棵树合并;否则不合并。

  • 然后就转化成了单点修改,区间查询问题了。

    点击查看代码
    ll f[50010],a[50010],sum[50010],L[50010],R[50010],pos[50010],klen,ksum;
    ll find(ll x)
    {
    	return (f[x]==x)?x:f[x]=find(f[x]);
    }
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    			sum[i]+=a[j];
    		}
    	}
    }
    void update(ll l,ll r)
    {
    	for(ll i=l;i<=r;i=find(i+1))
    	{
    		sum[pos[i]]+=sqrt(a[i])-a[i];
    		a[i]+=sqrt(a[i])-a[i];
    		f[i]=(a[i]<=1)?f[i+1]:f[i];
    	}
    }
    ll query(ll l,ll r)
    {
    	ll ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(ll i=l;i<=r;i++)
    		{
    			ans+=a[i];
    		}
    	}
    	else
    	{
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			ans+=a[i];
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			ans+=sum[i];
    		}
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			ans+=a[i];
    		}
    	}
    	return ans;
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    		f[i]=i;
    	}
    	f[n+1]=n+1;
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update(l,r);
    		}
    		else
    		{
    			printf("%lld\n",query(l,r));
    		}
    	}
    	return 0;
    }
    

2024年中国传媒大学程序设计大赛(同步赛)A 小苯的区间和疑惑

  • \([l,r]\) 拆成 \([l,i]\)\([i,r]\) 即可,然后就转化为 luogu P1115 最大子段和 了,使用 \(DP\) 求解即可。

    点击查看代码
    ll a[200010][2],f[200010][2];
    int main()
    {
    	ll n,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i][0];
    	}
    	for(i=1;i<=n;i++)
    	{
    		a[i][1]=a[n-i+1][0];
    	}
    	for(i=1;i<=n;i++)
    	{
    		f[i][0]=max(f[i-1][0],0ll)+a[i][0];
    		f[i][1]=max(f[i-1][1],0ll)+a[i][1];
    	}
    	for(i=1;i<=n;i++)
    	{
    		cout<<f[i][0]+f[n-i+1][1]-a[i][0]<<" ";
    	}
    	return 0;
    }
    

LibreOJ 6283. 数列分块入门 7

  • 优先更新整块的乘量标记 \(mul_{i}\)

  • 对散块进行修改时注意清空标记。

    点击查看代码
    const ll p=10007;
    ll a[100010],sum[100010],add[100010],mul[100010],L[100010],R[100010],pos[100010],klen,ksum;
    void init(ll n)
    {
    	klen=sqrt(n);
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		mul[i]=1;
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    ll query(ll l)
    {
    	return ((a[l]*mul[pos[l]])%p+add[pos[l]])%p;
    }
    void update_add(ll l,ll r,ll val)
    {   
    	if(pos[l]==pos[r])
    	{
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[l]]=1;
    		add[pos[l]]=0;
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]=(a[i]+val)%p;
    		}
    	}
    	else
    	{
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[l]]=1;
    		add[pos[l]]=0;
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]=(a[i]+val)%p;
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			add[i]=(add[i]+val)%p;
    		}
    		for(ll i=L[pos[r]];i<=R[pos[r]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[r]]=1;
    		add[pos[r]]=0;
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]=(a[i]+val)%p;
    		}
    	}
    }
    void update_mul(ll l,ll r,ll val)
    {
    	if(pos[l]==pos[r])
    	{
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[l]]=1;
    		add[pos[l]]=0;
    		for(ll i=l;i<=r;i++)
    		{
    			a[i]=(a[i]*val)%p;
    		}
    	}
    	else
    	{
    		for(ll i=L[pos[l]];i<=R[pos[l]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[l]]=1;
    		add[pos[l]]=0;
    		for(ll i=l;i<=R[pos[l]];i++)
    		{
    			a[i]=(a[i]*val)%p;
    		}
    		for(ll i=pos[l]+1;i<=pos[r]-1;i++)
    		{
    			mul[i]=(mul[i]*val)%p;
    			add[i]=(add[i]*val)%p;
    		}
    		for(ll i=L[pos[r]];i<=R[pos[r]];i++)
    		{
    			a[i]=query(i);
    		}
    		mul[pos[r]]=1;
    		add[pos[r]]=0;
    		for(ll i=L[pos[r]];i<=r;i++)
    		{
    			a[i]=(a[i]*val)%p;
    		}
    	}
    }
    int main()
    {
    	ll n,pd,l,r,val,i;
    	scanf("%lld",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld",&a[i]);
    		a[i]%=p;
    	}
    	init(n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld%lld",&pd,&l,&r,&val);
    		if(pd==0)
    		{
    			update_add(l,r,val);
    		}
    		if(pd==1)
    		{
    			update_mul(l,r,val);
    		}
    		if(pd==2)
    		{
    			printf("%lld\n",query(r));
    		}
    	}
    	return 0;
    }
    

luogu P7137 [THUPC2021 初赛] 切切糕

2024年中国传媒大学程序设计大赛(同步赛)D 小红的矩阵构造(一)

  • 由于是 \(1 \sim n\) 的排列,对于第 \(i\) 行满足 \(b_{j}>n-a_{i}\)\(b_{j}\) 恰好有 \(a_{i}\) 个,选择这些位置填 1 即可。第 \(i\) 列同理。

    点击查看代码
    int a[1010],b[1010];
    int main()
    {
    	int n,i,j;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(i=1;i<=n;i++)
    	{
    		cin>>b[i];
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			cout<<(b[j]>n-a[i]);
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    
posted @ 2024-03-13 14:18  hzoi_Shadow  阅读(66)  评论(1编辑  收藏  举报
扩大
缩小