2019-9-15 杂题选讲

2019-9-15 杂题选讲

题目

CF1174E Ehab and the Expected GCD Problem

link

这题给人的大概感觉就是,前缀 G C D GCD GCD是不增的,那么我们既然想要前缀 G C D GCD GCD尽量不同,我们必然希望它慢慢地下降,每次降一丢丢,那么我每次就只允许它降一半就是最优的咯,于是这就有了 N T F NTF NTF的结论的感性理解版。但是第一个数并不一定是 2 2 2的次幂,有可能带一个 3 3 3,因为乘最后一个 2 2 2时,如果加个 3 3 3不会爆 n n n,加个 3 3 3也是可以的。于是第一个数就是 2 x 3 y ( y = 1 o r 0 ) 2^x3^y(y=1 or 0) 2x3y(y=1or0),于是上 D P DP DP计数即可

[ZJOI2019]线段树

恭喜此题荣获本周的镇题之宝
link

震惊!天天打线段树的人竟不知线段树中有这五种点
这题的大致思路如下。首先每棵树的编号(相对顺序)是不影响答案的,我们只需要知道每次复制了一遍,新的 m o d i f y modify modify,旧的不动。那么我们设计状态 f u , i f_{u,i} fu,i表示i次操作后有多少个 u u u点有 t a g tag tag,我们将点分类之后分别写出 D P DP DP方程,发现还需维护一个 g u , i g_{u,i} gu,i表示 i i i次操作后有多少个 u u u点到 1 1 1的路径上没有 t a g tag tag,来辅助计算 f f f,这些线段树上的点经过分类后可以发现,有的是每次个数不超过 O ( l o g n ) O(logn) O(logn)级别,有的则是一棵小子树,那么前者暴力修改,后者用正常的 l a z y t a g lazy tag lazytag即可

CF1197D Yet Another Subarray Problem

link

这题就是推式子的时候令 i = ⌊ i m ⌋ ∗ m + i % m i=\lfloor \frac{i}{m}\rfloor *m+i \%m i=mim+i%m即可,由于m很小从左往右扫的时候维护前缀最小值时按%m分类即可

P4965 薇尔莉特的打字机

link

这题代码 e a s y easy easy但是思路 s o g o o d so good sogood。我们先考虑在 t r i e trie trie树上分析这个问题

  • 若一个把可以到达的点上做一个标记,那么加入一个字符时所有的标记点都拓展出一个新点,并且旧点仍然保留标记,那么我们就维护好 F [ c ] F[c] F[c]表示拥有边 c c c的节点个数即可快速转移
  • 若收到一个退格,多出来的答案就只有一个,就是原串从开始到这个退格之前的串,于是 a n s + + ans++ ans++,但是退格了之后相当于某个点向上走了一步,那么这个位置的点虽然已经有了一个标记,但是我们要把它当作两个点,于是 F [ x ] + + F[x]++ F[x]++,然后这题就没了

P2405 non天平

link

这题的思维难度不高,必然首先把物品转成 n n n进制,由于我们两边都能放砝码,相当于我们可以用一个大砝码减去一些小法码,从而得到原本用一些小砝码称出来的东西,但是这个相减的操作必定出现在大小相邻的两个砝码之间,而且必定大砝码只会用一个,除非我是傻的,那么从高到低 D P DP DP即可

代码

CF1174E Ehab and the Expected GCD Problem代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int mod=1e9+7;
int n,dp[N][21][2],lim=1,lg=0,ans;
int er[N],san[N];
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
inline int CAL(int x,int y)
{
	if (x<0||y<0) return 0;
	if (!er[x]||!san[y]) return 0;
	int ret=n/(er[x]*san[y]);
	return ret;
}
int main()
{
	mem(dp,0);
	n=read();
	while ((lim<<1)<=n) lim<<=1,lg++;
	er[0]=1;
	FOR(i,1,lg) er[i]=1LL*er[i-1]*2%mod;
	san[0]=1;
	for (register int i=1;san[i-1]*3<=n;i++) san[i]=1LL*san[i-1]*3%mod;
	dp[1][lg][0]=1;
	if (er[lg-1]*3<=n) dp[1][lg-1][1]=1;
	FOR(i,2,n)
		FOR(x,0,lg)
		{
			dp[i][x][0]=(1LL*dp[i-1][x][0]*(CAL(x,0)-i+1)%mod+1LL*dp[i-1][x][1]*(CAL(x,0)-CAL(x,1))%mod+1LL*dp[i-1][x+1][0]*(CAL(x,0)-CAL(x+1,0))%mod)%mod;
			dp[i][x][1]=(1LL*dp[i-1][x][1]*(CAL(x,1)-i+1)%mod+1LL*dp[i-1][x+1][1]*(CAL(x,1)-CAL(x+1,1))%mod)%mod;
		}
	ans=dp[n][0][0];
	write(ans);
	return 0;
}

[ZJOI2019]线段树代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int mod=998244353;
int n,m,cnt=1,opt,tmp1,tmp2,ans[N];
int sum[N<<2],f[N<<2],g[N<<2],tag_f[N<<2],tag_g[N<<2];
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
inline void up(int p)
{
	sum[p]=(1LL*sum[p<<1]+sum[p<<1|1]+f[p])%mod;
	return;
}
inline void bd(int p,int l,int r)
{
	sum[p]=f[p]=0;
	g[p]=1;
	tag_f[p]=tag_g[p]=1;
	if (l==r) return;
	int mid=(l+r)>>1,ls=p<<1,rs=p<<1|1;
	bd(ls,l,mid);
	bd(rs,mid+1,r);
	up(p);
	return;
}
inline void mul_f(int p,int v)
{
	tag_f[p]=1LL*tag_f[p]*v%mod;
	sum[p]=1LL*sum[p]*v%mod;
	f[p]=1LL*f[p]*v%mod;
	return;
}
inline void mul_g(int p,int v)
{
	tag_g[p]=1LL*tag_g[p]*v%mod;
	g[p]=1LL*g[p]*v%mod;
	return;
}
inline void down(int p)
{
	int ls=p<<1,rs=p<<1|1;
	if (tag_f[p]!=1)
	{
		mul_f(ls,tag_f[p]);
		mul_f(rs,tag_f[p]);
		tag_f[p]=1;
	}
	if (tag_g[p]!=1)
	{
		mul_g(ls,tag_g[p]);
		mul_g(rs,tag_g[p]);
		tag_g[p]=1;
	}
	return;
}
inline void md(int p,int l,int r,int L,int R)
{
	down(p);
	int mid=(l+r)>>1,ls=p<<1,rs=p<<1|1;
	if (L<=l&&r<=R)
	{
		mul_f(ls,2);mul_f(rs,2);
		f[p]=(1LL*f[p]+cnt)%mod;
		up(p);
		return;
	}
	g[p]=(1LL*g[p]+cnt)%mod;
	if (R<=mid)
	{
		md(ls,l,mid,L,R);
		down(rs);
		f[rs]=(1LL*f[rs]+cnt-g[rs]+mod)%mod;
		g[rs]=(1LL*g[rs]+g[rs])%mod;
		mul_g(rs<<1,2);mul_g(rs<<1|1,2);
		mul_f(rs<<1,2);mul_f(rs<<1|1,2);
		up(rs);
	}
	else if (L>mid)
	{
		md(rs,mid+1,r,L,R);
		down(ls);
		f[ls]=(1LL*f[ls]+cnt-g[ls]+mod)%mod;
		g[ls]=(1LL*g[ls]+g[ls])%mod;
		mul_g(ls<<1,2);mul_g(ls<<1|1,2);
		mul_f(ls<<1,2);mul_f(ls<<1|1,2);
		up(ls);
	}
	else
	{
		md(ls,l,mid,L,R);
		md(rs,mid+1,r,L,R);
	}
	up(p);
	return;
}
int main()
{
//	freopen("data.in","r",stdin);
	n=read(),m=read();
	bd(1,1,n);
	FOR(i,1,m)
	{
		opt=read();
		if (opt==1) tmp1=read(),tmp2=read();
		if (opt==1) md(1,1,n,tmp1,tmp2),cnt=(1LL*cnt+cnt)%mod;
		else ans[++ans[0]]=sum[1];
	}
	FOR(i,1,ans[0]) write(ans[i]),putchar('\n');
	return 0;
}

CF1197D Yet Another Subarray Problem代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register ll i=(a);i<=(b);i++)
#define For(i,a,b) for (register ll i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register ll j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const ll N=3e5+5;
const ll inf=1e17;
ll n,m,k,a[N],s[N],mn[20],r[N],tmp,ans=0;
inline ll read()
{
	ll x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(ll x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
int main()
{
	n=read(),m=read(),k=read();
	FOR(i,1,m-1) mn[i]=inf;
	FOR(i,1,n) a[i]=read();
	FOR(i,1,n) s[i]=s[i-1]+a[i];
	FOR(i,1,n) r[i]=s[i]-k*(i/m);
	FOR(i,1,n)
	{
		tmp=i%m;
		FOR(j,0,m-1) ans=max(ans,r[i]-mn[j]-k*((i%m-j+m-1)/m));
		mn[tmp]=min(mn[tmp],r[i]);
	}
	write(ans);
	return 0;
}

P4965 薇尔莉特的打字机代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=5e6+5;
const int mod=19260817;
int n,m,ans=1,rest,F[100];
char A[N],B[N];
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
int main()
{
	n=read(),m=read();
	rest=n;
	scanf("%s",A+1);
	scanf("%s",B+1);
	FOR(i,1,m)
	{
		int c=B[i]-'A'+1;
		if (1<=c&&c<=26)
		{
			int f=F[c];
			F[c]=ans;
			ans=(1LL*(ans<<1)-f+mod)%mod;
		}
		else
		{
			if (!rest) continue;
			ans++;
			ans%=mod;
			F[A[rest]-'A'+1]++;
			F[A[rest]-'A'+1]%=mod;
			rest--;
		}
	}
	write(ans);
	return 0;
}

P2405 non天平代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e6+5;
int n,s[N],tmps[N],len=0,r[N],dp[N][2],ans;
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
inline int get_yu()
{
	int ret=0;
	FOR(i,1,len)
	{
		ret=(ret<<1)+(ret<<3)+s[i];
		ret%=n;
	}
	return ret;
}
inline void devide()
{
	int now=0,tmplen=0,ready=0;
	FOR(i,1,len) tmps[i]=0;
	FOR(i,1,len)
	{
		now=(now<<1)+(now<<3)+s[i];
		if (now>=n) ready=1;
		if (ready)
		{
			tmps[++tmplen]=now/n;
			now%=n;
		}
	}
	len=tmplen;
	FOR(i,1,len) s[i]=tmps[i];
	return;
}
int main()
{
//	freopen("testdata (1).in","r",stdin);
	char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') s[++len]=c-'0',c=getchar();
	scanf("%d",&n);
	if (n==1) {FOR(i,1,len) write(s[i]);exit(0);}
	while (len)
	{
		r[++r[0]]=get_yu();
		devide();
	}
	dp[r[0]+1][1]=1;
	For(i,r[0],1)
	{
		dp[i][0]=min(dp[i+1][0]+r[i],dp[i+1][1]+n-r[i]);
		dp[i][1]=min(dp[i+1][0]+r[i]+1,dp[i+1][1]+n-r[i]-1);
	}
	ans=dp[1][0];
	write(ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值