A 中国剩余定理,I 树状数组解决偏序问题,G回文树
题目链接:https://nanti.jisuanke.com/t/41383
这里出题人强行套了一个中国剩余定理。。。
#include
using namespace std;
#define ll long long
const int maxn=2000;
ll n,m;
ll ai[maxn],bi[maxn];
ll sum[maxn];
ll N=1e16;
ll mul(ll a,ll b,ll mod){
ll res=0;
while(b>0){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){x=1;y=0;return a;}
ll gcd=exgcd(b,a%b,x,y);
ll tp=x;
x=y; y=tp-a/b*y;
return gcd;
}
ll excrt(){
ll x,y,k;
ll M=bi[1],ans=ai[1];
for(int i=2;i<=n;i++){
ll a=M,b=bi[i],c=(ai[i]-ans%b+b)%b;
ll gcd=exgcd(a,b,x,y),bg=b/gcd;
if(c%gcd!=0) return -1;
x=x*c/gcd%bg;
ans+=x*M;
M*=bg;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main()
{
int len=73;
sum[0]=1;
sum[1]=1;
for(int i=2;i<=len;++i)sum[i]=sum[i-1]+sum[i-2];
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld%lld",&bi[i],&ai[i]);
ll ans=excrt();
//ans=13;
//printf("ans:%lld\n",ans);
if(ans<=1||ans>N){
printf("Tankernb!");
return 0;
}
bool flag=0;
for(int i=1;i<=len;++i)
{
if(sum[i]==ans){
printf("Lbnb!");
return 0;
}
}
printf("Zgxnb!");
return 0;
}
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
struct node
{
int ty,val;
}a[2*N];
int X[2*N];
int sum[8*N];
int len;
int getid(int x)
{
return lower_bound(X+1,X+1+len,x)-X;
}
void build(int id,int l,int r)
{
sum[id]=r-l+1;
if(l==r) return ;
int mid=l+r>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
}
void up(int id,int l,int r,int pos)
{
sum[id]--;
if(l==r) return ;
int mid=l+r>>1;
if(pos<=mid) up(id<<1,l,mid,pos);
else up(id<<1|1,mid+1,r,pos);
}
bool flag;
int ans;
void qu(int id,int l,int r,int ql,int qr)
{
if(l==r){
if(sum[id])
{
flag=1;
ans=X[l];
}
return ;
}
int mid=l+r>>1;
if(!flag&&ql<=mid&&sum[id<<1]) qu(id<<1,l,mid,ql,qr);
if(!flag&&sum[id<<1|1]) qu(id<<1|1,mid+1,r,ql,qr);
}
int main()
{
int n,q;
cin>>n>>q;
rep(i,1,q)
{
scanf("%d%d",&a[i].ty,&a[i].val);
X[++len]=a[i].val;
X[++len]=a[i].val+1;
}
sort(X+1,X+1+len);
len=unique(X+1,X+1+len)-X-1;
build(1,1,len);
rep(i,1,q)
{
if(a[i].ty==1) up(1,1,len,getid(a[i].val));
else{
flag=0;
ans=-1;
qu(1,1,len,getid(a[i].val),len);
printf("%d\n",ans);
}
}
}
#include
using namespace std;
#define ll long long
int w;
int main(){
scanf("%d",&w);
if(w%2==0&&w!=2){
printf("YES\n");
}else printf("NO\n");
}
#include
#define ll long long
using namespace std;
const int N = 3e5 + 10;
//base[i]进制
ll h[3][N],h1[3][N];
ll base[3]={43,47,41};
ll mod[3] = {1000000007,998244353,1000000009};
ll f[3][N];
inline int getid(char c) {
return c-'a'+1;
}
char s[N],t[N];
void init()
{
f[1][0]=f[0][0]=f[2][0]=1;
for(int i=1;imp[3];
int main()
{
init();
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;++i)
for(int j=0;j<3;++j)
h[j][i]=(h[j][i-1]*base[j]%mod[j]+getid(s[i]))%mod[j];
int q;
scanf("%d",&q);
while(q--)
{
scanf("%s",t+1);
int m=strlen(t+1);
for(int i=1;i<=m;++i)
{
for(int j=0;j<3;++j)
h1[j][i]=(h1[j][i-1]*base[j]%mod[j]+getid(t[i]))%mod[j];
}
if(n>m)
{
bool f=0;
for(int i=1;i+m-1<=n&&!f;++i)
{
bool flag=1;
for(int j=1;j<3;++j)
{
if(h1[j][m]==getvalue(i,i+m-1,j)) continue;
else flag=0;
}
if(flag) f=1;
}
if(f) printf("my child!\n");
else printf("oh, child!\n");
}else if(n
#include
using namespace std;
#define ll long long
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
const int N=5e5+7;
int t[N*4];
ll n,m,a[N];
ll Ans[N];
int len=0;
ll X[N*2];
int getid(ll x) {return lower_bound(X+1,X+1+len,x)-X;}
void updata(int rt,int l,int r,int pos,int x){
if(l==r){
t[rt]=x;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) updata(rt<<1,l,mid,pos,x);
else updata(rt<<1|1,mid+1,r,pos,x);
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
int query(int rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
return t[rt];
}
int mid=(l+r)>>1,res=0;
if(ql<=mid) res=max(res,query(rt<<1,l,mid,ql,qr));
if(qr>mid) res=max(res,query(rt<<1|1,mid+1,r,ql,qr));
return res;
}
int main(){
n=input(),m=input();
for(int i=1;i<=n;i++){
a[i]=input();
X[++len]=a[i];
}
sort(X+1,X+1+len);
len=unique(X+1,X+1+len)-X-1;
for(int i=1;i<=n;i++){
updata(1,1,len,getid(a[i]),i);
}
for(int i=1;i<=n;i++){
if(a[i]+m
补题来自:https://blog.csdn.net/HNUCSEE_LJK/article/details/100638270
题面:
由于给的是一个排列,所以我可以nlogn的时间复杂求出所有符合题目条件的(i,j)出来,如何实现,看代码。。。
常见的二维偏序 形式:每个单位 (a, b) 找到有多少 (x, y) 满足 a > x 且 b < y。
这里就是每个单位(l,r),有多少(i,j) 满足l
这里的二维偏序怎么处理呢?
我学的那篇题解讲的不错,就是字多,看起来难受,细心的看,还是很好理解的。
首先,读入数据时,我们将每个值对应的位置记录下来。然后,对于 [1, n] 的每个值 p[i],找出序列中与 p[i] 成倍数关系的值 p[j](p[j] = k*p[i], k = 2, 3, 4...),得到它的位置 j,并与 i 构成一个区间 [i, j],可以称之为贡献区间。若 [i, j] 在查询的范围 [l, r] 之内,那么就能为答案贡献 +1。当我们找到所有这样的区间时,将这些贡献区间与询问区间混合,并进行排序,
排序的规则是按照区间的左端点从大到小排列,当贡献区间与询问区间的左端点相同时,则贡献区间在前。然后依次处理每个区间。
枚举区间,当遇到贡献区间时,贡献区间的右端点在树状数组上加1,当遇到询问区间时,答案加上 树状数组 1到询问区间右端点的和。最后,由于询问是离线处理的,所以要根据询问的顺序依次输出答案。
至于为什么,因为区间先按左端点从大到小枚举。遇到的询问区间,询问区间的左端点一定包含了 之前出现的贡献区间的左端点。那么只需要查询有多少个右端点比询问区间的右端点小的就可以了。
代码:
#include
using namespace std;
const int N=1e5+10;
int p[N],pos[N],a[N];
int n,m;
int sum[N],ans[N];
int low(int x)
{
return x&(-x);
}
struct node
{
int l,r,id,f;
bool operator <(const node &o)const
{
if(o.l!=l) return l>o.l;
return f>o.f;
}
}q[N*40];
void up(int x)
{
for(;x<=n;x+=low(x))
sum[x]++;
}
int qu(int x)
{
int res=0;
for(;x;x-=low(x)) res+=sum[x];
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
pos[a[i]]=i;
}
int len=0;
for(int i=1;i<=m;++i)
{
int l,r;scanf("%d%d",&l,&r);
q[++len]={l,r,i,0};
}
for(int i=1;i<=n;++i)
for(int j=2;i*j<=n;++j)
q[++len]={min(pos[i],pos[i*j]),max(pos[i],pos[i*j]),0,1};
/*
for(int i=1;i<=n;++i)
for(int j=2*a[i];j<=n;j+=a[i])
q[++len]={min(i,pos[j]),max(i,pos[j]),0,1};
*/
sort(q+1,q+1+len);
for(int i=1;i<=len;++i)
{
if(q[i].f) up(q[i].r);
else ans[q[i].id]=qu(q[i].r);
}
for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
#include
using namespace std;
#define ll long long
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
#define PII pair
#define x first
#define y second
#define mp make_pair
const int N=1007;
int n;
PII pt[N];
map mpp;
vector mid;
int main(){
n=input();
for(int i=1;i<=n;i++){
pt[i].x=2ll*input(),pt[i].y=2ll*input();
}
ll mx=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
PII tmp=mp((pt[i].x+pt[j].x)/2,(pt[i].y+pt[j].y)/2);
mpp[tmp]++;
if(mpp[tmp]>mx) mx=mpp[tmp];
}
}
// cout<
思路很容易想到,枚举t串,在s串中出现大于t[i]的s[j]那么s的后面都要取。
那么做法就是枚举t串,枚举比当前t[i]大的字符,在s串中序列自动机找一找,若有,更新一下答案。
接着判断是否有与t[i]相等的,有 继续枚举t串,没有 break掉。其实很水,思路当时也出了,自己也会序列自动机 ,可为什么这个题当时没A。。。。
#include
using namespace std;
const int N=1e6+10;
char s[N],t[N];
int nxt[N][27];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
scanf("%s%s",s+1,t+1);
for(int i=n;i>=1;i--)
{
for(int j=0;j<=25;j++) nxt[i-1][j]=nxt[i][j];
nxt[i-1][s[i]-'a']=i;
}
int ans=-1;
int cur=0,pre=0;
for(int i=1;i<=m;++i)
{
for(int j=t[i]-'a'+1;j<=25;++j)
{
int ne=nxt[pre][j];
if(ne==0) continue;//没有找到
ans=max(ans,cur+n-ne+1);
}
int ne=nxt[pre][t[i]-'a'];
if(ne==0) break;
cur++;pre=ne;
if(i==m&&n>m) ans=max(ans,cur+n-ne);
}
printf("%d\n",ans);
}