北京Day 8

调了一晚上T1,留坑待补

今日得分:40+60+100

T1

题目大意:给出一个长度为 N 的序列 A[n]和 M 个操作,操作分为两种类型: 类型一,给出参数 l r k b 对于 l 到 r 之间(闭区间)的所有数 i ,令 A[i] = max(A[i],k*(i-l)+b ) 类型二,给出参数 l r, 求出 A[l] 到 A[r] 共(r-l+1)个数之中的最大值 n<=50000

李超线段树裸题,每次修改线段时,如果覆盖则直接覆盖,如果不能覆盖,则将这条线段递归到交点所在的区间即可。

T1AC代码(来自某位好心的同学)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
struct line
{
	int k,b;
	int f(int x){return k*x+b;}
};
struct node{int mx,ma;line ml;}s[N<<2];
void ins(line sg,int l,int r,int ql,int qr)
{
	if(l>r||ql>r||qr<l)return;
	int mid=l+r>>1;
	if(ql<=mid&&mid<=qr)s[mid].mx=max(s[mid].mx,sg.f(mid));
	s[mid].ma=max(s[mid].ma,max(sg.f(max(l,ql)),sg.f(min(r,qr))));
	if(ql<=l&&r<=qr)
	{
		int x=sg.f(mid);
		if(x>s[mid].ml.f(mid))swap(s[mid].ml,sg);
		if(sg.k<s[mid].ml.k)ins(sg,l,mid-1,ql,qr);
		else ins(sg,mid+1,r,ql,qr);
	}
	else ins(sg,l,mid-1,ql,qr),ins(sg,mid+1,r,ql,qr);
}
int qry(int l,int r,int ql,int qr)
{
	int mid=l+r>>1;
	if(l>r||ql>r||qr<l)return -1e9;
	int ret=max(s[mid].ml.f(max(l,ql)),s[mid].ml.f(min(r,qr)));
	if(ql<=mid&&mid<=qr)ret=max(ret,s[mid].mx);
	if(ql<=l&&r<=qr)return max(ret,s[mid].ma);
	else ret=max(ret,max(qry(l,mid-1,ql,qr),qry(mid+1,r,ql,qr)));
	return ret;
}
int main()
{
	int n,m,i,j,k,x,y,z,l,r,b,o;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&b);
		ins((line){0,b},1,n,i,i);
	}
	while(m--)
	{
		scanf("%d%d%d",&o,&l,&r);
		if(o==1)
		{
			scanf("%d%d",&k,&b);
			ins((line){k,b-k*l},1,n,l,r);
		}
		else
		{
			printf("%d\n",qry(1,n,l,r));
		}
	}
}

T2

题目大意:给出一个正整数序列,求一个连续子序列,使得这个连续子序列的GCD与长度的乘积最大化,并输出最大值。n<=100000

题解:枚举右端点,用单调栈维护每个不同的gcd值最靠左的元素,转移右端点时将其加入栈顶,更新一下单调栈,去重即可。

T2AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<bitset>
#include<map>
using namespace std;
inline long long re_ad()
{
	long long x=0;int f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();return x*f;
}
inline long long ma(long long x,long long y){return x>y?x:y;}
int n,cnt,top;
long long ans,a[100010];
struct node{long long num;int ii;}z[100010];
long long gcd(long long x,long long y){return (y)?gcd(y,x%y):x;}
int main()
{
	register long long x;
	n=re_ad();
	for(int i=1;i<=n;i++)a[i]=re_ad();
	for(register int i=1;i<=n;i++)
	{
	z[++top].num=a[i];z[top].ii=i;
	for(register int j=1;j<=top;j++){z[j].num=gcd(z[j].num,a[i]);}
	cnt=0;
	for(register int j=1;j<=top;j++){if(z[j].num!=z[j-1].num)z[++cnt]=z[j];}
	top=cnt;
	for(register int j=1;j<=top;j++)ans=ma(ans,z[j].num*(i-z[j].ii+1));
	}
	cout<<ans<<endl;return 0;
}

T3

题目大意:

给定个集合 ? ,元素个数 |?|=? 。对于 ? 的任意一个子集合 ? ,定义 ?(?)=|?|^? ,定义 ? 关于 ? 的补集为 ?−? 。等概率地选择一个 ?的子集 ?,求 ?(?)−?(?−?)的方差。设其为 ?,输出 (?⋅2^?)mod? 。

题解:(打表找规律)大力推式子

T3AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<bitset>
#include<map>
using namespace std;
inline int re_ad()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();return x*f;
}
char s[1000010];
int n1,n2,k,m,pre[1000010],ni[1000010],a[1000010];
long long zts,ans,an[1000010];
inline int ksm(int a,int b)
{int ret=1;while(b){if(b&1)ret=1ll*ret*a%m;b>>=1;a=1ll*a*a%m;}return ret;}
inline long long c(int x,int y){if(x<y)return 0;return 1ll*pre[x]*ni[y]%m*ni[x-y]%m;}
long long L(int x,int y){if(!y)return 1;return L(x/m,y/m)*c(x%m,y%m)%m;}
int main()
{
	scanf("%s",s+1);
	k=re_ad();m=re_ad();
	int l=strlen(s+1);
	for(register int i=1;i<=l;++i){n1=(n1*10+s[i]-48)%m;n2=(n2*10+s[i]-48)%(m-1);a[i]=s[i]-48;}
	zts=ksm(2,n2);
	pre[0]=1;for(int i=1;i<m;i++)pre[i]=1ll*pre[i-1]*i%m;
	ni[m-1]=ksm(pre[m-1],m-2);
	for(int i=m-2;i>=0;i--)ni[i]=1ll*ni[i+1]*(i+1)%m;
	for(register int i=0;i<=(n1-1>>1);++i)
	{
	an[i]=(ksm(i,k)-ksm(n1-i,k))%m;an[i]=an[i]*an[i]%m;
	ans=(ans+1ll*L(n1,i)*an[i]%m)%m;
	}
	ans=(ans<<1)%m;ans=ans*ksm(zts,m-2)%m;ans=1ll*ans*ksm(2,n2)%m;
	int now=0,z=1,y=l;
	for(register int i=1;i<=l;++i)
	{
	now=(now*10+a[i]);a[i]=now/m;now%=m;
	}
	while(a[z]==0)z++;
	n2=0;
	for(register int i=z;i<=l;++i)n2=(n2*10+a[i])%(m-1);
	ans=1ll*ans*ksm(2,n2)%m;
	cout<<ans<<endl;
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值