Codeforces Round #539 (Div. 1)

A.

显然就是统计有多少区间长度为偶数且xor为0

#include<bits/stdc++.h>
using namespace std;
int n,x;
int f[2000010][2];
long long ans;
int main()
{
	scanf("%d",&n);
	f[0][0]=1;
	int s=0;
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&x); s^=x; 
        ans+=(long long)f[s][i&1];
        f[s][i&1]++;
	}
	cout << ans << endl;
}

B.

题目让你求至少把原字符串切成几段,才能使他们重新排列后为回文串且与原来的串不同

首先我们发现如果一个回文串所有字符都相等(长度为偶数)或除却中间字符其余字符都相等(长度为奇数)的话,那么他们必然是impossible

否则那么他们的答案必然是小于等于2的我们只要从开始找到第一个与前面不同的的字符与其回文的后缀交换即可

那么我们最后在暴力判一下只分成两端是不是可以

#include<bits/stdc++.h>
using namespace std;
char s[5010];
int main()
{
	scanf("%s",s+1);
	int len=strlen(s+1);
	if (len<=3) cout << "Impossible" << endl;
	else {
		bool p=0;
		for (int i=2;i<=len/2;i++)
            if (s[i]!=s[i-1])
            {
            	p=1; break;
            }
        if (!p) cout << "Impossible" << endl;
        else {
        	for (int i=1;i<len;i++)
        	{
        		bool p=0;
        		for (int j=i+1;j<=len;j++)
        			 if (s[j]!=s[j-i]) {p=1; break;}
        		for (int j=1;j<=i;j++)
        		     if (s[j]!=s[len-i+j]) {p=1; break;}
        		if (!p) continue;     	
        		for (int j=0;j<min(i,len-i);j++)
        			 if (s[i-j]!=s[i+1+j]) {
        			 	p=0; break;
        			 }
        		int l,r;	 
        		if (i>len-i) l=1,r=len-(len-i)*2; else l=i*2+1,r=len;
        		for (int j=l;j<=r;j++)
        		    if (s[j]!=s[r+l-j]) {p=0; break;} 	 
        		if (p) {
        			cout << 1 << endl; return 0;
        		}	 	
        	}
        	cout << 2 << endl;
        }          
	}
}

C.

这道题应该是数据结构题,但是由于博主码完E题之后已经失去信仰了,所以他就咕了

D.

这道题应该就是一道你知道这个知识点就做的出来的题目,不知道就gg了

cayley定理,即我那篇树的计数博客中所讲到的东西(不知道的话可以去看一下)

然后这道题又是他的另一种扩展应用

首先我们显然需要枚举两个点a,b之间有多少条边(或者有多少点也可以,下文是以枚举边来考虑的,i表示已经枚举了i条变)

即我们考虑一下prufer序列,但是,由于我们已经确定了某些点之间的联系,所以我们应该在一开始的点集中删去那些点,所以我们考虑一下剩余的prufer序列长度就是n-i-1,他的限制在于最后被删除的点与之相连的点是已选中的那i+1个点,剩余的就和prufer序列一样

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int MAXN=1e6+10;
const int N=1e6;
ll inv[MAXN],fac[MAXN];
int n,m,a,b;
ll ksm(ll x,ll y)
{
	ll ans=1;
	for (;y;y>>=1,x=(x*x)%mod) if (y&1) ans=(ans*x)%mod;
	return ans;
}
ll C(int x,int y)
{
	if (x<0||y<0||x<y) return 0;
	return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&a,&b);
	fac[0]=1;
	for (int i=1;i<=N;i++) fac[i]=(fac[i-1]*(ll)i)%mod;
	inv[0]=inv[1]=1;
    for (int i=2;i<=N;i++) inv[i]=(mod-mod/(ll)i)*inv[mod%i]%mod;
    for (int i=2;i<=N;i++) inv[i]=(inv[i-1]*inv[i])%mod;
    ll s,ans=0;
	for (int i=1;i<=min(n-1,m);i++)
	{
		ll s=(ksm(m,n-i-1)*C(m-1,i-1)%mod*C(n-2,i-1)%mod*fac[i-1]%mod);
		if (i<n-1) s=(s*(ll)(i+1)%mod*ksm(n,n-i-2)%mod);
		ans=(ans+s)%mod;
	}
	cout << ans << endl;
}

E.

这道题太过于毒瘤,码量巨大(主要是博主菜

首先我们思考一下发现这个mod数是制约,如果这个模数是很大的质数的话我们就可以就直接有线段树维护就行了,逆元的话直接exgcd求一下就行了

但是这道题他的逆元可能不存在,那么怎么办呢?

我们发现一个事实,即他的模数是给你的,即我们可以把这个模数的质因子给预处理出来,那么以后每个数都只要去除这些质因子就行了(这样的话就可以求逆元了啦),由于2*3*5*7*11*13*17*19*23*29>1e9+9所以模数的质因子个数是不会超过10的我们只需开个树状数组维护一下他们质因子的个数就行了

剩余的就是维护非这些质因子的区间信息和原来的数的区间信息,由于他们涉及到区间乘操作,所以用线段树来维护

那么我们思考一下对于第一个操作,只要区间乘区间加

对于第二个操作只要考虑一下单点减,然后暴力取出这个位置的有关质因子的个数暴力算贡献,最后剩余的数求一下逆元,最后所得的这个位置上的数直接单点修改就行了

码量大(实际上博主的代码比较丑)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN=1e5+10;
const int N=1e5;
struct node{
	LL ans,po;
};
node tree[12][MAXN<<2];
LL xx,yy;
int n,l,r,q,opt,p,len;
int c[MAXN];
int prime[MAXN];
LL mod,b[MAXN],x,a[MAXN];
bool o[MAXN];
/**********************************************************************************/
LL ksm(LL x,LL y)
{
	LL ans=1;
	for (;y;y>>=1,x=(x*x)%mod) if (y&1) ans=(ans*x)%mod;
	return ans;
}
void exgcd(LL x,LL y)
{
	if (y==0)
	{
         xx=1; yy=0;
	}
	else {
		exgcd(y,x%y);
		LL p=xx; xx=yy;yy=p-(x/y)*yy;
	}
}
void mul(LL &x,LL y)
{
	x=(x*y)%mod;
}
LL push(LL x,LL y)
{
	return (x+y)%mod;
}
int lowbit(int x)
{
	return x&(-x);
}
/**********************************************************************************/
void init()
{
	for (int i=2;i<=N;i++)
	{
		if (!o[i]) {
			prime[++len]=i;
		}
		for (int j=1;prime[j]*i<=N&&j<=len;j++)
		{
			o[prime[j]*i]=1;
			if (i%prime[j]==0) break;
		}
	}
}
void make(int x)
{
	for (int i=1;i<=len;i++)
		if (x%prime[i]==0)
		{
			b[++p]=prime[i];
			while (x%prime[i]==0) x/=prime[i];
		}
	if (x>1) b[++p]=x;	
}
/**********************************************************************************/
void update(int now,int k)
{
	tree[now][k].ans=(tree[now][k<<1].ans+tree[now][k<<1|1].ans)%mod;
}
void build(int now,int l,int r,int k)
{
	if (l==r)
	{
		tree[now][k].ans=c[l]%mod;
	}
	else {
		int mid=(l+r)/2;
		build(now,l,mid,k<<1); build(now,mid+1,r,k<<1|1);
		update(now,k);
	}
}
void pushdown(int now,int k)
{
	if (tree[now][k].po!=1) 
	{
		mul(tree[now][k<<1].ans,tree[now][k].po); mul(tree[now][k<<1].po,tree[now][k].po);
		mul(tree[now][k<<1|1].ans,tree[now][k].po); mul(tree[now][k<<1|1].po,tree[now][k].po);
		tree[now][k].po=1;
	}
}
/**********************************************************************************/
LL findans(int l,int r,int k,int ll,int rr)
{
	if (l==ll&&r==rr)
	{
		return tree[0][k].ans;
	}
	else {
		int mid=(l+r)/2;
		pushdown(0,k);
		if (rr<=mid) return findans(l,mid,k<<1,ll,rr);
		else if (ll>mid) return findans(mid+1,r,k<<1|1,ll,rr);
		else return push(findans(l,mid,k<<1,ll,mid),findans(mid+1,r,k<<1|1,mid+1,rr));
	}
}
/**********************************************************************************/
void change1(int now,int l,int r,int k,int ll,int rr,LL x)
{
     if (l==ll&&r==rr)
     {
     	mul(tree[now][k].po,x);
     	mul(tree[now][k].ans,x);
     }
     else {
     	int mid=(l+r)/2;
     	pushdown(now,k);
     	if (rr<=mid) change1(now,l,mid,k<<1,ll,rr,x);
     	else if (ll>mid) change1(now,mid+1,r,k<<1|1,ll,rr,x);
     	else {
     		change1(now,l,mid,k<<1,ll,mid,x); change1(now,mid+1,r,k<<1|1,mid+1,rr,x);
     	}
     	update(now,k);
     }
} 
void add(int now,int t,int x)
{
     while (t<=n) {
         tree[now][t].ans+=x; t+=lowbit(t);
     }
}
//opt1
void la(int x,int l,int r)
{
	change1(0,1,n,1,l,r,x%mod);
	for (int i=1;i<=p;i++)
		if (x%b[i]==0)
		{
			int s=0;
			while (x%b[i]==0) {
				s++; x/=b[i];
			}
			add(i,l,s); add(i,r+1,-s);
		}
	change1(p+1,1,n,1,l,r,x%mod);	
}
/**********************************************************************************/
int get(int now,int t)
{
	int ans=0;
	while (t) 
	{
		ans+=tree[now][t].ans; t-=lowbit(t);
	}
	return ans;
}
int changedel(int now,int t,int s)
{
    add(now,t,-s); add(now,t+1,s);
    return get(now,t);
}
LL changela(int now,int l,int r,int k,int t,LL s)
{
	if (l==r) {
		mul(tree[now][k].ans,s);
		return tree[now][k].ans;
	}
	else {
		int mid=(l+r)/2;
		pushdown(now,k);
		LL ans=0;
		if (t<=mid) {
			ans=changela(now,l,mid,k<<1,t,s);
		} else ans=changela(now,mid+1,r,k<<1|1,t,s);
		update(now,k);
		return ans;
	}
}
void changeput(int now,int l,int r,int k,int t,LL s)
{
	if (l==r)
	{
		tree[now][k].ans=s;
	}
	else {
		int mid=(l+r)/2;
		pushdown(now,k);
		if (t<=mid) changeput(now,l,mid,k<<1,t,s);
		else changeput(now,mid+1,r,k<<1|1,t,s);
		update(now,k);
	}
}
//opt2
void solve(int t,LL x)
{
	LL ans=1;
	for (int i=1;i<=p;i++)
		 {
		 	int s=0;
		 	while (x%b[i]==0) 
		 	{
		 		x/=b[i]; s++;
		 	}
		 	mul(ans,ksm(b[i],changedel(i,t,s)));
		 }  	 
	exgcd(x%mod,mod);
	xx=(xx%mod+mod)%mod;
	mul(ans,changela(p+1,1,n,1,t,xx));
	changeput(0,1,n,1,t,ans);	
}
/**********************************************************************************/
int main()
{
	scanf("%d%lld",&n,&mod);
	init();
	make(mod);
	for (int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for (int i=1;i<=n;i++) c[i]=a[i];
	build(0,1,n,1);
	for (int i=1;i<=(n<<2);i++) tree[0][i].po=1;
	for (int i=1;i<=p;i++)
	{
		for (int j=1;j<=n;j++)
		{
			c[j]=0;
			while (a[j]%b[i]==0) 
			{
				c[j]++; a[j]/=b[i];
			}
			add(i,j,c[j]);
			add(i,j+1,-c[j]);
		}
	}
	for (int i=1;i<=(n<<2);i++) tree[p+1][i].po=1;
	for (int i=1;i<=n;i++) c[i]=a[i];
	build(p+1,1,n,1);	
	scanf("%d",&q);
	for (int i=1;i<=q;i++)
	{
		scanf("%d",&opt);
		if (opt==1){
			scanf("%d%d%lld",&l,&r,&x);
			la(x,l,r);
		}
		else if (opt==2) {
			scanf("%d%lld",&l,&x);
			solve(l,x);
		}
		else {
			scanf("%d%d",&l,&r);
			printf("%lld\n",findans(1,n,1,l,r));
		}
	}
}

F.

因为博主太菜了,所以他咕了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值