额 掰手指头一数 特么又是第三年十连测了= =

2017一场没打 那时候好像一场比赛也就100人左右

2018前几场还都好好补了 后来开始放飞自我了 这时候一场有150人还多了

2019想让今年的Noip不留遗憾 好像一场有200人多 现在好的能冲进前十不好也就三四十

主要是把题解里可以借鉴的思路和代码罗列一下

一。

A.(ZROI954)

考虑对这玩意dp pi=1等价于右括号 pi=2等价于左括号 pi=3等价于左右任选括号 我们需要让其括号匹配的代价尽量小 然后排序顺序按照能力值大小,相等时按照231来排就可以了 分析复杂度 发现k是sqrt(n)级别的 所以总复杂度是O(nsqrt(n)) 但是要注意dp数组不能memset。。不然会让复杂度分析凉掉。。(这个代码是后来手机改的所以格式有点奇怪。。。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 500
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
struct node{int type,w,s;}a[];
bool cmp(node x,node y)
{
if(x.w!=y.w) return x.w<y.w;
return x.type<y.type;
}
ll f[][N+][N+];
int main()
{
//freopen("ex_group3.in","r",stdin);
int n=read(),k=read();
for(int i=;i<=n;i++)
{
a[i].w=read(),a[i].s=read(),a[i].type=read();
if(a[i].type==) a[i].type=;
else if(a[i].type==) a[i].type=;
else a[i].type=;
}
if(n<*k){printf("-1\n"); return ;}
sort(a+,a+n+,cmp);
memset(f,,sizeof(f));
f[][][]=; int p=;
for(int i=;i<=n;i++)
{
p^=;// memset(f[p],48,sizeof(f[p]));
for(int j=;j<=k;j++) for(int l=;l+j<=k;l++)
{ f[p][j][l]=f[p][N][N];
}
for(int j=;j<=k;j++) for(int l=;l+j<=k;l++)
{
f[p][j][l]=min(f[p][j][l],f[p^][j][l]);
if(a[i].type== || a[i].type==)
{
if(l) f[p][j][l]=min(f[p][j][l],f[p^][j][l-]+a[i].s);
}
if(a[i].type== || a[i].type==)
{
if(j) f[p][j][l]=min(f[p][j][l],f[p^][j-][l+]+a[i].s);
}
//printf("%d %d %d %lld\n",p,j,l,f[p][j][l]);
}
}
p^=; memset(f[p],,sizeof(f[p]));
if(f[p^][k][]==f[p][][]) printf("-1");
else printf("%lld\n",f[p^][k][]);
return ;
}

A

B.(ZROI955)

先考虑一维的做法 我们发现折起来其实相当于把短的一边砍掉 然后发现对于一个答案区间[l,r]合法相当于[1,r]&&[l,n]都合法(脑补一下

最后的话就是分别统计计数就好了 继续考虑二维的做法 我们发现行列之间互不影响 最后答案是行列乘起来就好了

对于单纯行来说 我们把列直接哈希掉就可以了 我单哈也过了(@lky 快点砸ZR

//Love and Freedom.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<vector>
#define ll long long
#define inf 20021225
#define md 20040423
#define bs 37
#define str string
#define pb push_back
#define N 1000010
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
vector<str> vec; str ch; vector<int> pos;
int hs1[N],hs2[N],cnt; int a[N<<],f[N<<];
ll calc(int cnt,int n)
{
pos.clear();
int len,mx=,mr=,p=,ans=; pos.pb();
for(int i=;i<=cnt;i++)
{
if(mr>=i) f[i]=min(f[(p<<)-i],mr-i);
while(i+f[i]<=cnt&&i-f[i]>=&&a[i+f[i]]==a[i-f[i]]) f[i]++;
if(i+f[i]>mr) mr=i+f[i],p=i;
mx=max(mx,f[i]-);
if(!(i&) && i!=)
{
int id=i>>;
if(f[i-]>=*(id-ans)+)
ans=id,pos.pb(id);
}
}
ans=n; int tmp=pos.size()-; ll cur=;
for(int i=cnt;i;i--)
{
if(!(i&))
{
int id=i>>;// printf("%d %d %d %d\n",i,id,f[i+1],2*(ans-id)+1);
if(f[i+]>=*(ans-id)+)
{
while(~tmp && pos[tmp]>id) tmp--;
cur+=tmp+; ans=id;
}
}
}
return cur;
}
int main()
{
int n=read(),m=read();
for(int i=;i<n;i++)
cin>>ch,vec.pb(ch);
for(int i=;i<n;i++)
{
int hs=;
for(int j=;j<m;j++) hs=(1ll*hs*bs%md+vec[i][j]-'a'+)%md;
hs1[i]=hs;
}
cnt=; a[++cnt]=;
for(int i=;i<n;i++) a[++cnt]=hs1[i],a[++cnt]=;
ll ans=calc(cnt,n);// printf("%d\n",ans);
for(int i=;i<m;i++)
{
int hs=;
for(int j=;j<n;j++) hs=(1ll*hs*bs%md+vec[j][i]-'a'+)%md;
hs2[i]=hs;// printf("%d\n",hs);
}
cnt=; a[++cnt]=;// printf("%d\n",ans);
for(int i=;i<m;i++) a[++cnt]=hs2[i],a[++cnt]=;
printf("%lld\n",ans*calc(cnt,m));
return ;
}

B

C.(ZROI956)

神仙题ovo!0/1操作已经把trie暗示的很明显了。我们发现+1会对后缀连续一段1进行翻转。所以我们反过来建trie。然后异或可以打整体标记。好像就做完了ovo。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define ll long long
#define inf 20021225
#define N 300010
#define ls(x) t[x].son[0]
#define rs(x) t[x].son[1]
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct node{int son[],tag,ed;}t[N*];
int poi,k;
void insert(int s)
{
int pos=;
for(int i=;i<;i++)
{
int ch=(s>>i&)^(k>>i&);
if(!t[pos].son[ch]) t[pos].son[ch]=++poi;
pos=t[pos].son[ch];
}
t[pos].ed++;
}
void del(int x)
{
int pos=;
for(int i=;i<;i++)
{
int ch=(x>>i&)^(k>>i&);
if(!t[pos].son[ch]) t[pos].son[ch]=++poi;
pos=t[pos].son[ch];
}
t[pos].ed--;// printf("GG");
}
void add()
{
int pos=;
for(int i=;i<;i++)
{
int ch=(k>>i&);
swap(ls(pos),rs(pos));
if(!t[pos].son[ch]) break;
pos=t[pos].son[ch];
}
}
vector<int> ans;
void dfs(int pos,int val,int d)
{
for(int i=;i<=t[pos].ed;i++) ans.push_back(val);
if(d==) return; int ch=k>>d&;
if(t[pos].son[ch]) dfs(t[pos].son[ch],val,d+);
if(t[pos].son[ch^]) dfs(t[pos].son[ch^],val^(<<d),d+);
}
int main()
{
int n=read(),q=read(),x;
for(int i=;i<=n;i++)
x=read(),insert(x);
while(q--)
{
int opt=read(); if(opt!=) x=read();
if(opt==) insert(x);
else if(opt==) del(x);
else if(opt==) add();
else k^=x;
}
dfs(,,); sort(ans.begin(),ans.end());
for(int i=;i<ans.size();i++) printf("%d ",ans[i]);
return ;
}

C

二。

A.(ZROI957)

先求出部分解再调整得到整体解的思路值得借鉴。首先可以想到贪心一定可以求出一组解(前提:解存在)

然后我们考虑倒着调整这组解,我们发现对于S中i和i+1两个位置如果不一样的话 那么这两个中间一定要有一个被匹配(题目要求)然后我们发现每次选最往后的调整一定是不劣的,所以直接暴力扫一遍就可以了。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 300010
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
char s[N],t[N]; int n,m,pos[N]; bool vis[N];
int main()
{
n=read(),m=read(); scanf("%s%s",s+,t+); int i,p;
for(i=,p=;i<=n && p<=m;i++)
if(s[i]==t[p]) pos[p++]=i;
if(p<=m) return printf("-1\n"),;
for(i=n-,p=m;i&&pos[p]<i&&p;i--)
if(s[i]!=s[i+] && !vis[i+]) pos[p]=s[i]==t[p]?i:i+,vis[pos[p]]=,p--;
if(!p) for(;i;i--) if(s[i]!=s[i+] && !vis[i+]) return printf("-1\n"),;
for(int i=;i<=m;i++) printf("%d ",pos[i]);
return ;
}

A

B.(ZROI958)

我们考虑二分k,显然可以倍增建图O(nlg^2n)但是常数较大容易wei掉。我们考虑用并查集替换这个过程,因为图是一棵基环树,所以用并查集维护bfs直接把环断掉就OK了。好神仙啊。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define ll long long
#define inf 20021225
#define N 300010
#define pa pair<int,int>
#define fs first
#define se second
#define mp make_pair
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
int n,to[N][];
struct bcj
{
int fa[N],dis[N]; bool vis[N];
void init()
{
for(int i=;i<=n;i++)
vis[i]=dis[i]=,fa[i]=i;
}
int find(int x)
{
if(x==fa[x]) return x;
int fx=find(fa[x]); dis[x]+=dis[fa[x]];
return fa[x]=fx;
}
}c[];
queue<pa> q;
bool check(int k)
{
c[].init(); c[].init(); while(!q.empty()) q.pop();
q.push(mp(,)); q.push(mp(,)); c[].vis[]=c[].vis[]=;
while(!q.empty())
{
pa tmp=q.front(); q.pop(); int x=tmp.fs,s=tmp.se; x=to[x][s];
while(inf)
{
int fx=c[s].find(x); if(c[s^].vis[fx]) break;
if(c[s].dis[x]>=k) break; if(fx==n) return ;
c[s^].vis[fx]=; q.push(mp(fx,s^));
if(c[s].find(to[fx][s])==fx) break;
c[s].fa[fx]=to[fx][s]; ++c[s].dis[fx];
}
}
return ;
}
int main()
{
n=read(); for(int i=;i<=n;i++) to[i][]=read(),to[i][]=read();
int l=,r=n,ans=-;
while(l<=r)
{
int mid=l+r>>;
if(check(mid)) ans=mid,r=mid-;
else l=mid+;
}
printf("%d\n",ans);
return ;
}

B

C.(ZROI959)

常规套路好题。考虑每个数的质因数不超过7个,所以我们可以直接对于每个质因数暴力建图(其实也不需要建出来 直接在搜索的时候判一下边权就可以了)然后我们需要找到对于每个质因数过u,v的最长链,如果有一个最长链和原树中最长链一样的话答案就是n+1不然的话就是所有长度取max+1 一个很好的写法就是dfs(x,fa,p)用fa直接ban掉一个方向的路径。最后复杂度是O(nlgnlgw)。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 200010
#define P 1000000
#define pa pair<int,int>
#define mp make_pair
#define fs first
#define se second
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
int gcd(int x,int y){return y?gcd(y,x%y):x;}
struct edge{int to,lt,v;}e[N<<];
int F[N][],dep[N],G[N][]; bool vis[P];
int f[N][],g[N],in[N],cnt;
void add(int x,int y,int v)
{
e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].v=v; in[x]=cnt;
e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].v=v; in[y]=cnt;
}
void getfa(int x)
{
for(int i=;i<;i++) F[x][i]=F[F[x][i-]][i-],G[x][i]=gcd(G[x][i-],G[F[x][i-]][i-]);
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to; if(y==F[x][]) continue;
F[y][]=x; G[y][]=e[i].v; dep[y]=dep[x]+; getfa(y);
}
}
pa jump(int x,int l)
{
int g=;
for(int i=;i<;i++) if(l>>i&)
g=gcd(G[x][i],g),x=F[x][i]; return mp(x,g);
}
pa LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
pa tmp=jump(x,dep[x]-dep[y]); x=tmp.fs;
if(x==y) return tmp; int g=tmp.se;
for(int i=;~i;i--) if(F[x][i]!=F[y][i])
g=gcd(gcd(G[y][i],G[x][i]),g),x=F[x][i],y=F[y][i];
return mp(F[x][],gcd(gcd(G[x][],G[y][]),g));
}
int solve(int x,int fa,int p)
{
int ans=;
for(int i=in[x];i;i=e[i].lt)
{
if(e[i].v%p) continue;
int y=e[i].to; if(y==fa) continue;
ans=max(ans,solve(y,x,p)+);
}
return ans;
}
bool np[P+]; int pri[N],tot,lt[P+];
void sieve()
{
for(int i=;i<=P;i++)
{
if(!np[i]) pri[++tot]=i,lt[i]=i;
for(int j=;j<=tot&&i*pri[j]<=P;j++)
{
np[i*pri[j]]=; lt[i*pri[j]]=pri[j]; if(i%pri[j]==) break;
}
}
}
int main()
{
sieve(); int n=read(),q=read(),x,y,v;
for(int i=;i<n;i++) x=read(),y=read(),v=read(),add(x,y,v);
getfa();
while(q--)
{
x=read(),y=read(); pa tmp=LCA(x,y);
if(tmp.se==){printf("%d\n",dep[x]+dep[y]-*dep[tmp.fs]); continue;}
int fx=tmp.fs==x?jump(y,dep[y]-dep[x]-).fs:F[x][];
int fy=tmp.fs==y?jump(x,dep[x]-dep[y]-).fs:F[y][];
int mx=solve(x,fx,)+solve(y,fy,); int ans=;
while(tmp.se!=)
{
int g=lt[tmp.se]; while(tmp.se%g==) tmp.se/=g;
ans=max(ans,solve(x,fx,g)+solve(y,fy,g));
if(ans==mx) break;
}
if(ans==mx) ans=-;
else ans+=dep[x]+dep[y]-*dep[tmp.fs]+;
printf("%d\n",ans);
}
return ;
}

C

三。

A.(ZROI960)

斯波题。枚举答案,然后用lower_bound查找即可。复杂度分析用到调和级数:O(nlg^2n) 话说这题暴力跑的比lg^2快咋整啊。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 100010
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
int pre[][N],n; char ch[N];
int calc(int s)
{
int pos=,ans=,flag=;
while(pos<=n)
{
pos=lower_bound(pre[]+pos+,pre[]+n+,pre[][pos]+s)-pre[];
if(pos>n) return flag>?ans-:; ans+=s; flag++;
pos=lower_bound(pre[]+pos+,pre[]+n+,pre[][pos]+)-pre[];
if(pos>n) return flag>?ans:; flag++; ans++;
}
}
int main()
{
scanf("%s",ch+); n=strlen(ch+); int ans=;
for(int i=;i<=n;i++) pre[][i]+=(ch[i]==''),pre[][i]+=(ch[i]=='');
for(int i=;i<=n;i++) pre[][i]+=pre[][i-],pre[][i]+=pre[][i-];
for(int s=;s<n;s++) ans=max(ans,calc(s));
printf("%d\n",pre[][n]?ans:);
return ;
}

A

B.(ZROI961)

神仙题。sun切了。场上做法做的是bitset优化转移。正解的话,可以发现如果我们有三个数x,y,z 且满足$\frac{1}{1.1}z <= x <= y <=z$的话,y是没有必要存下来的,而$log_{1.1} 2e15$只有370,所以我们可以暴力转移保存。如果使用sort的话时间复杂度是lglg,所以使用归并排序即可。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
#define inf 20021225
#define N 200010
#define it vector<ll>::iterator
#define vec vector<ll>
#define pb push_back
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct edge{int to,lt; ll v;}e[N];
int in[N],cnt,n,m; vector<ll> len[N],tmp;
queue<int> q; int d[N],a[N],top;
void add(int x,int y,ll v)
{
e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].v=v; in[x]=cnt; d[y]++;
}
void pushback(ll val)
{
if(tmp.size()>= && tmp[tmp.size()-]*/>=val)
tmp.pop_back();
tmp.pb(val);
}
void merge(vec a,vec b,ll va,ll vb,vec &c)
{
it i=a.begin(),j=b.begin(); tmp.clear(); ll val;
while(i<a.end() && j<b.end())
{
if((*i)+va==(*j)+vb)
val=(*i)+va,i++,j++;
else if((*i)+va<(*j)+vb)
val=(*i)+va,i++;
else
val=(*j)+vb,j++;
pushback(val);
}
while(i<a.end())
val=(*i)+va,i++,pushback(val);
while(j<b.end())
val=(*j)+vb,j++,pushback(val);
c=tmp;
}
void ins2(int x,int y,ll v)
{
merge(len[x],len[y],v,,len[y]);
}
void ins(int x)
{
for(int i=in[x];i;i=e[i].lt) ins2(x,e[i].to,e[i].v);
}
int main()
{
n=read(),m=read(); int Q=read(),x,y; ll v;
for(int i=;i<=m;i++) x=read(),y=read(),scanf("%lld",&v),add(x,y,v);
for(int i=;i<=n;i++) if(!d[i]) q.push(i);
while(!q.empty())
{
int x=q.front(); q.pop(); a[++top]=x;// printf("%d\n",x);
for(int i=in[x];i;i=e[i].lt)
if(!(--d[e[i].to])) q.push(e[i].to);
}
len[].pb();
for(int i=;i<=top;i++) ins(a[i]);
while(Q--)
{
int x=read(); scanf("%lld",&v);
it i=lower_bound(len[x].begin(),len[x].end(),v);
if(i!=len[x].end() && (*i)<=v*/) printf("YES\n");
else printf("NO\n");
}
return ;
}

B

C.(ZROI962)

大数据结构题(雾。最后0.5h突然就会了,然后写了个暴力还写挂了(MMP。 发现我们只需要线段树分别维护行列极值,然后分三种情况讨论一下就可以了。其中一种情况需要线段树上二分,我好像写丑了常数有点大...不过这种题写起来是真的神清气爽。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 100010
#define ls (x<<1)
#define rs (x<<1|1)
#define mid (l+r>>1)
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct SGT
{
int mn[N<<],mx[N<<],n;
void pushup(int x)
{
mn[x]=min(mn[ls],mn[rs]);
mx[x]=max(mx[ls],mx[rs]);
}
void modify(int x,int l,int r,int d,int v)
{
if(l==r){mn[x]=mx[x]=v; return;}
if(d<=mid) modify(ls,l,mid,d,v);
else modify(rs,mid+,r,d,v);
pushup(x);
}
int query(int x,int l,int r,int LL,int RR,int f)
{
if(LL<=l&&r<=RR){return f?mx[x]:mn[x];}
int ans=f?:inf;
if(LL<=mid) ans=f?max(ans,query(ls,l,mid,LL,RR,f)):min(ans,query(ls,l,mid,LL,RR,f));
if(RR>mid) ans=f?max(ans,query(rs,mid+,r,LL,RR,f)):min(ans,query(rs,mid+,r,LL,RR,f));
return ans;
}
int pquery(int x,int l,int r,int LL,int RR,int v)
{
if(l==r) return mx[x]>=v?l:-;
if(LL<=l&&r<=RR)
{
if(mx[rs]>=v) return pquery(rs,mid+,r,LL,RR,v);
if(mx[ls]>=v) return pquery(ls,l,mid,LL,RR,v);
return -;
}
int ans=-;
if(LL<=mid) ans=max(ans,pquery(ls,l,mid,LL,RR,v));
if(RR>mid) ans=max(ans,pquery(rs,mid+,r,LL,RR,v));
return ans;
}
int squery(int x,int l,int r,int LL,int RR,int v)
{
if(l==r) return mx[x]>=v?l:inf;
if(LL<=l&&r<=RR)
{
if(mx[ls]>=v) return squery(ls,l,mid,LL,RR,v);
if(mx[rs]>=v) return squery(rs,mid+,r,LL,RR,v);
return inf;
}
int ans=inf;
if(LL<=mid) ans=min(ans,squery(ls,l,mid,LL,RR,v));
if(RR>mid) ans=min(ans,squery(rs,mid+,r,LL,RR,v));
return ans;
}
int nqry(int l,int r,int v)
{
int tmp1=pquery(,,n,,l,v);
int tmp2=squery(,,n,r,n,v);
if(tmp1==-) return tmp2==inf?-:tmp2-r;
return tmp2==inf?l-tmp1:min(l-tmp1,tmp2-r);
}
int qry(int l,int r,int f){return query(,,n,l,r,f);}
void mdf(int d,int v){modify(,,n,d,v);}
}t[];
void modify(int x,int f,int v){t[f].mdf(x,v);}
int query(int a,int b,int c,int d,int v)
{
int mht=abs(b-d)+abs(c-a);
if(t[].qry(a,a,)>=v && t[].qry(d,d,)>=v) return mht;
if(t[].qry(b,b,)>=v && t[].qry(c,c,)>=v) return mht;
if(a>c) swap(a,c); if(b>d) swap(b,d);
if(t[].qry(a,c,)>=v || t[].qry(b,d,)>=v) return mht;
int ans=inf;
if(t[].qry(a,a,)>=v && t[].qry(c,c,)>=v)
{
if(t[].qry(b,d,)>=v) return mht;
int tmp=t[].nqry(b,d,v);
if(~tmp) ans=min(ans,tmp);
}
if(t[].qry(b,b,)>=v && t[].qry(d,d,)>=v)
{
if(t[].qry(a,c,)>=v) return mht;
int tmp=t[].nqry(a,c,v);
if(~tmp) ans=min(ans,tmp);
}
return ans==inf?-:mht+(ans<<);
}
int main()
{
int n=read(),m=read(),q=read(),x;
t[].n=n; t[].n=m;
for(int i=;i<=q;i++)
{
int opt=read();
if(opt==)
{
int a=read(),b=read(),c=read(),d=read(),v=read();
printf("%d\n",a==c&&b==d?:query(a,b,c,d,i-v));
}
else
x=read(),modify(x,opt-,i);
}
return ;
}

C

四。

A.(ZROI963)

疯狂分类讨论即可...

大概长这样...最后一个也需要考虑字典序所以光荣的获得了90分的好成绩...

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 500100
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
char s1[N],s2[N]; int n1,n2;
void sub1()
{
for(int i=;i<=n1;i++)
printf("%c",s1[i]==s2[i]?s1[i]:'?');
printf("\n");
}
int pre[N],suf[N];
void sub2()
{
if(n1>n2) swap(n1,n2),swap(s1,s2);
pre[]=suf[n1+]=; int ans=,pos=;
for(int i=;i<=n1;i++) pre[i]=pre[i-]+(s1[i]==s2[i] && s1[i]!='?');
for(int i=;i<n1;i++) suf[n1-i]=suf[n1-i+]+(s1[n1-i]==s2[n2-i] && s1[n1-i]!='?');
for(int i=;i<=n1;i++)
if(pre[i]+suf[i+]>ans){ans=pre[i]+suf[i+]; pos=i;}
for(int i=;i<=pos;i++) printf("%c",s1[i]==s2[i]?s1[i]:'?');
printf("*");
for(int i=pos+;i<=n1;i++) printf("%c",s1[i]==s2[n2-n1+i]?s1[i]:'?');
printf("\n");
}
char qwq[N];
void sub3()
{
memset(pre,,sizeof(pre)); memset(suf,,sizeof(suf));
if(n1>n2) swap(n1,n2),swap(s1,s2);
int d=,pos=n1+;
int c1=,c2=,k=;
for(int i=;i<=n1;i++) c1+=s1[i]!='*';
for(int i=;i<=n2;i++) c2+=s2[i]!='*';
c1=min(c1,c2);
for(int i=n1;i;i--)
if(s1[i]=='*' || s2[n2-n1+i]=='*') break;
else if(s1[i]==s2[n2-n1+i]&&s1[i]!='?') d++,pos=i;
int m=d;
for(int i=;i<=n1;i++)
{
if(s1[i]=='*'||s2[i]=='*') break;
if(i>=pos&&s2[n2-n1+i]==s1[i]) d--;
if(s1[i]==s2[i]&&s1[i]!='?') d++;
if(d>m) m=d,k=i;
}
for(int i=;i<=k;i++) printf("%c",s1[i]==s2[i]?s1[i]:'?');
printf("*");
if(k>=pos)
{
for(int i=n2-n1+k+,j=k+;j<=n1;i++,j++) printf("%c",s1[j]==s2[i]?s1[j]:'?');
}
else
{
for(int i=;i<=c1-k-n1+pos-;i++) printf("?");
for(int i=n2-n1+pos,j=pos;j<=n1;i++,j++) printf("%c",s1[j]==s2[i]?s1[j]:'?');
}
printf("\n");
}
int main()
{
int T=read();
while(T--)
{
scanf("%s%s",s1+,s2+); int flag=;
n1=strlen(s1+),n2=strlen(s2+);
for(int i=;i<=n1;i++) flag|=(s1[i]=='*');
for(int i=;i<=n2;i++) flag|=(s2[i]=='*');
if(flag)
{
sub3();
}
else
{
if(n1==n2) sub1();
else sub2();
}
}
return ;
}
/**
ab*cd
a*c
*/

A

B.(ZROI964)

二分以后需要和n无关的判断 发现柿子长这样(pi-pj+1)>=2*(i-j+1)

移项以后可以通过单调性维护

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define ll long long
#define inf 20021225
#define P 1000010
#define N 500010
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct node{int i,p;}; vector<node> f[P];
bool cmp(node a,node b){return a.p-*a.i<b.p-*b.i;}
int pri[N],cnt,a[N],lt[P]; bool np[P];
void prime(int n)
{
for(int i=;i<=n;i++)
{
if(!np[i]) pri[++cnt]=i,lt[i]=i;
for(int j=;j<=cnt && i*pri[j]<=n;j++)
{
np[i*pri[j]]=,lt[i*pri[j]]=pri[j]; if(i%pri[j]==) break;
}
}
}
int mx[N],mp[N],n;
pair<int,int> work(vector<node> t)
{
sort(t.begin(),t.end(),cmp); mx[]=t[].i; mp[]=t[].p;
for(int i=;i<t.size();i++)
{
if(t[i].i>mx[i-]) mx[i]=t[i].i,mp[i]=t[i].p;
else mx[i]=mx[i-],mp[i]=mp[i-];
}
int l=,ans=,al=;
for(int i=;i<t.size();i++)
{
while(l<t.size()- && t[l+].p-*t[l+].i <= t[i].p-*t[i].i+) l++;
int len=;// printf("%d %d %d %d %d\n",i,l,t[i].i,t[i].p,mn[l]);
if(t[l].p-*t[l].i<=t[i].p-*t[i].i+) len=*(mx[l]-t[i].i+);
//printf("%d %d\n",mp[l],len);
if(len>ans) ans=len,al=max(,mp[l]-len+);
else if(len==ans) al=min(al,max(,mp[l]-len+));
}
//printf("%d %d\n",ans,al);
return make_pair(ans,al);
}
int main()
{
prime(1e6); n=read();
for(int i=;i<=n;i++) a[i]=read();
for(int i=;i<=n;i++)
while(a[i]!=)
{
int g=lt[a[i]]; while(a[i]%g==) a[i]/=g;
f[g].push_back(node{f[g].size()+,i});
}
pair<int,int> fin=make_pair(,),tmp;
for(int i=;i<=cnt;i++)
{
if(f[pri[i]].size()<) continue;
tmp=work(f[pri[i]]);// printf("%d %d\n",tmp.first,tmp.second);
if(tmp.first>fin.first) fin=tmp;
else if(tmp.first==fin.first) fin.second=min(tmp.second,fin.second);
}
printf("%d %d\n",fin.second,max(,min(n,fin.second+fin.first-)));
return ;
}
/**
10
43 11 65 53 54 51 91 17 19 31
*/

C.(ZROI965)

考虑y爆零阶段的x 和 以后的x 它们如果不存在有0的 那么他们的和应该=x

所以对于一个i有效的状态只有O(x)个 可以通过把状态压起来来做到O(1)转移

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
#define inf 20021225
#define M 4010
#define N 2010
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct node{int a,b,id;}v[N];
bool operator<(node a,node b){return a.a>b.a;}
int n,x,y,pre[N],w,f[N][M*],pp[N][M*],pq[N][M*];
bool kd[N][M*]; queue<int> ze,nz;
void decode(int s,int i,int &p,int &q)
{
if(s>=M){p=; q=s-M;}
else{p=s; q=max(,x-pre[i]-p);}
}
int encode(int p,int q)
{
if(p) return p;
else return q+M;
}
void upd(int i,int p,int q,int fp,int fq,int val,int t)
{
int s=encode(p,q);
if(f[i][s]<val)
{
f[i][s]=val; pp[i][s]=fp; pq[i][s]=fq; kd[i][s]=t;
}
}
void getper(int x,int p,int q)
{
if(!x) return;
int s=encode(p,q);
getper(x-,pp[x][s],pq[x][s]);
if(kd[x][s]) nz.push(v[x].id);
else ze.push(v[x].id);
}
int main()
{
x=read(),n=read();
for(int i=;i<=n;i++) v[i].a=read();
for(int i=;i<=n;i++) v[i].b=read(),v[i].id=i;
sort(v+,v+n+); memset(f,-,sizeof(f));
for(int i=;i<=n;i++) pre[i]=pre[i-]+v[i].a;
for(int i=;i<=x;i++) f[][encode(i,x-i)]=;
for(int i=;i<=n;i++) for(int j=;j<M*;j++)
if(f[i-][j]>=)
{
int p,q; decode(j,i-,p,q);
upd(i,max(p-v[i].a,),q,p,q,f[i-][j]+v[i].b+min(v[i].a-p,),);
upd(i,p,max(q-v[i].a,),p,q,f[i-][j],);
}
int ans=-,pos=;
for(int i=;i<M*;i++) if(f[n][i]>ans)
{
int p,q; decode(i,n,p,q);
if(!q) ans=f[n][i],pos=p;
}
getper(n,pos,);
printf("%d\n",ans);
while(!ze.empty()) printf("%d ",ze.front()),ze.pop();
while(!nz.empty()) printf("%d ",nz.front()),nz.pop();
return ;
}

C

五。

A.(ZROI966)

我可能是一种奇特的推法...

考虑贪心匹配的话一定是尽量往前匹配...所以每个位置如果不匹配下一位的话是(c-1)种方案,否则是匹配,然后考虑容斥,选出i个位置(i<m)是匹配位,这样的话用总方案-算出来的就是答案了。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define mdn 1000000007
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
int ksm(int bs,int mi)
{
int ans=;
while(mi)
{
if(mi&) ans=1ll*ans*bs%mdn;
bs=1ll*bs*bs%mdn; mi>>=;
}
return ans;
}
int main()
{
int n=read(),m=read(),c=read();
for(int i=;i<=m;i++)
int x=read();
int ans=ksm(c,n),fn=,fm=;
ans=(ans-ksm(c-,n)%mdn+mdn)%mdn;
for(int i=;i<m;i++)
{
fn=1ll*fn*(n-i+)%mdn, fm=1ll*fm*i%mdn;
ans=(ans-1ll*fn*ksm(fm,mdn-)%mdn*ksm(c-,n-i)%mdn+mdn)%mdn;
}
printf("%d\n",(ans+mdn)%mdn);
return ;
}

A

B.(ZROI967)

神仙题...

发现是翻硬币游戏模型,打个表可以发现sg[i]=2^lowbit(i) 然后用双射f[i]=2^(lowbit(i)+1)-1来表示(这样依然显然可以保证sg异或的性质)

接下来我们只需要维护每一位有多少1就可以了,最后的答案就是sum的最高位1的个数(因为在r的最高位为1的话前面的一定可以选出区间来保证凑出任何最高位为1的数 可以感性理解一下也可以通过异或基来证明)

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define lowbit(x) ((x)&(-x))
#define N 1<<20
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
int f[N],a[N],pre[]; char ch[N];
int main()
{
int n=read(),sum=;
for(int i=;i<=n;i++) f[i]=(lowbit(i)<<)-;
scanf("%s",ch+);
reverse(ch+,ch+n+);
for(int i=;i<=n;i++)
if(ch[i]=='')
{
sum^=f[i]; a[i]=;
for(int j=;j<;j++) if(i>>j&)
pre[j]++;
}
int m=read();
while(m--)
{
int x=read(); x=n-x+; a[x]^=; sum^=f[x];
if(a[x])
{
for(int j=;j<;j++) if(x>>j&)
pre[j]++;
}
else
{
for(int j=;j<;j++) if(x>>j&)
pre[j]--;
} if(!sum) puts("");
else
{
for(int j=;~j;j--) if(sum>>j&)
{
printf("%d\n",pre[j]); break;
}
}
}
return ;
}

B

C.(ZROI968)

我在学习了...别催了...《Re:从零开始的群论生活》

学完了(。

我有一个绝妙的解释,但这里放不下。(逃

一些小地方的理解:

首先奇质数可以直接做的原因是因为奇质数有原根,那么它相当于直接的循环群。

而2^a不好做的原因就是因为它没有原根,但是2^a的群可以分解成一个循环群和一个二阶群的直积。

具体证明详见《抽象代数》(逃

话说为什么我的跑的这么慢啊...

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 1000000001
#define mdn 1000000007
#define N 10000001
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
int ksm(int bs,int mi)
{
int ans=;
while(mi)
{
if(mi&) ans=1ll*ans*bs%mdn;
bs=1ll*bs*bs%mdn; mi>>=;
}
return ans;
}
int inv(int x){return ksm(x,mdn-);}
int S(int p,int l,int r,int k){return 1ll*(ksm(p,r+k)-ksm(p,l)+mdn)%mdn*inv(ksm(p,k)-)%mdn;}
int a[N],b[N],pri[N],cnt,mp[N]; bool np[N];
void sieve()
{
for(int i=;i<N;i++)
{
if(!np[i]) pri[++cnt]=i,mp[i]=i;
for(int j=;j<=cnt&&i*pri[j]<N;j++)
{
np[pri[j]*i]=; mp[pri[j]*i]=pri[j];
if(pri[j]%i==) break;
}
}
}
int fac[],top;
int get(int x)
{
int ans=; top=;
while(x!=){fac[++top]=mp[x]; x/=mp[x];}
for(int i=,s=;i<=top;i++,s++) if(i==top||fac[i]!=fac[i+])
{
while(s>b[fac[i]]) ans*=fac[i],s--;
s=;
}
return ans;
}
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
int solve_pri(int p,int k)
{
int ans=; int l=(a[p]-)%k+,r=a[p],m=b[p];
//printf("%d %d %d\n",r,k,ans);
if(r>k) upd(ans,S(p,l-m+k-,r-m-,k)); // a-ik-1>0
upd(ans,ksm(p,max(,l-m-))); // last
return (1ll*get(p-)*ans%mdn+)%mdn;
}
int solve_2(int k)
{
if(!b[]) return solve_pri(,k);
int ans=; int l=(a[]-)%k+,r=a[],m=b[];
if(r>k) upd(ans,S(,l-m+k-,r-m-,k));
upd(ans,ksm(,max(,l-m-min(l,))));
return (ans+)%mdn;
}
int main()
{
sieve();
int n=read();
for(int i=;i<=n;i++)
{
int x=read(),y=read();
a[x]=y;
}
int m=read();
for(int i=;i<=m;i++)
{
int x=read(),y=read();
b[x]=y;
}
int k=,ans=;
for(int i=;i<=cnt&&k<inf;i++)
for(int j=;j<=b[pri[i]]&&k<inf;j++)
k=min(1ll*inf,1ll*k*pri[i]);
ans=a[]?solve_2(k):; //printf("%d\n",k);
for(int i=;i<=cnt;i++) if(a[pri[i]])
ans=1ll*ans*solve_pri(pri[i],k)%mdn;
printf("%d\n",ans);
return ;
}

C

六。

A.(ZROI969)

真·NOIPCSP T1

考虑两者作差就可以证明只要整除N-1就可以了 最后就是N-1的约数个数。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
int main()
{
int P=read(),ans=; P--;
for(int i=;i<=P;i++) if(P%i==) ans++;
printf("%d\n",ans);
return ;
}

A

B.(ZROI970)

按照套路gcd==i都可以转化为gcd|i来做,然后最后直接容斥

那么发现gcd|i直接通过统计因数计算贡献就可以了。

本来以为这个复杂度是NK后来写着写着发现md这就是n*d(n)= =

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 400010
#define mdn 998244353
#define rg register
#define il inline
#include<ctime>
using namespace std;
il int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
int a[N],d[N],n,m,k,fac[N],inv[N],f[N];
il int ksm(int bs,int mi)
{
int ans=;
while(mi)
{
if(mi&) ans=1ll*ans*bs%mdn;
bs=1ll*bs*bs%mdn; mi>>=;
}
return ans;
}
il int C(int n,int m)
{
if(n<m) return ;
return 1ll*fac[n]*inv[m]%mdn*inv[n-m]%mdn;
}
//void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
#define upd(x,y) (x+=x+y>=mdn?y-mdn:y)
// 洪蛤吨是大毒瘤!!!卡我nsqrtn!!!
// wdnmd 我再用upd我就是憨憨(卡常去世选手
int pri[N],cnt,mn[N]; bool np[N];
il void sieve(int n)
{
for(int i=;i<=n;i++)
{
if(!np[i]) pri[++cnt]=i,mn[i]=i;
for(int j=;j<=cnt&&pri[j]*i<=n;j++)
{
np[i*pri[j]]=pri[j]; mn[i*pri[j]]=pri[j];
if(i%pri[j]==) break;
}
}
}
int stk[],top,tms[];
il void dfs(int x,int v)
{
if(x>top){d[v]++; return;} int dv=v;
for(int i=;i<=tms[x];i++)
dfs(x+,dv),dv*=stk[x];
}
il void takedown(int x)
{
top=;// printf("%d\n",x);
while(x!=)
{
stk[++top]=mn[x]; tms[top]=; int gg=mn[x];
while(x%gg==) tms[top]++,x/=gg;
}
//printf("%d %d %d %d\n",tms[1],tms[2],stk[1],stk[2]);
dfs(,);
}
int main()
{
//freopen("960.in","r",stdin);
n=read(),m=read(),k=read();
//sieve(m);
//printf("%lld ",clock());
for(rg int i=;i<=n;i++)
{
a[i]=read(); d[a[i]]++;
//takedown(a[i]);
}
for(rg int i=;i<=m;i++) for(rg int j=i+i;j<=m;j+=i)
d[i]+=d[j];
//printf("%lld ",clock());
//for(int i=1;i<=m;i++) printf("%d\n",d[i]);
fac[]=; //int tot=0;
//for(int i=1;i<=m;i++) tot+=d[i];
//printf("%d\n",tot);
for(rg int i=;i<=n;i++) fac[i]=1ll*fac[i-]*i%mdn;
inv[n]=ksm(fac[n],mdn-);
for(rg int i=n;i;i--) inv[i-]=1ll*inv[i]*i%mdn;
for(rg int i=;i<=m;i++)
{
int ans=,qwq=m/i,tmp=; ans=ksm(qwq,d[i]);
int qaq=; int j;
for(j=n-d[i];j<k-;j+=)
{
qaq=(qaq+1ll*tmp*C(d[i],j-n+d[i])%mdn)%mdn,tmp=1ll*tmp*(qwq-)%mdn;
qaq=(qaq+1ll*tmp*C(d[i],j-n++d[i])%mdn)%mdn,tmp=1ll*tmp*(qwq-)%mdn;
qaq=(qaq+1ll*tmp*C(d[i],j-n++d[i])%mdn)%mdn,tmp=1ll*tmp*(qwq-)%mdn;
qaq=(qaq+1ll*tmp*C(d[i],j-n++d[i])%mdn)%mdn,tmp=1ll*tmp*(qwq-)%mdn;
}
for(;j<k;j++)
upd(qaq,1ll*tmp*C(d[i],j-n+d[i])%mdn),tmp=1ll*tmp*(qwq-)%mdn;
ans=(ans-qaq+mdn)%mdn;
f[i]=1ll*ans*ksm(qwq,n-d[i])%mdn;
}
//printf("%lld ",clock());
for(rg int i=m;i;i--) for(rg int j=i+i;j<=m;j+=i)
f[i]=(f[i]-f[j]+mdn)%mdn;
for(rg int i=;i<=m;i++) printf("%d ",f[i]);
return ;
}

B

C.(ZROI971)

考场上写50由于先写了20的暴力就差一点改完= =(不过主要的锅应该在T2卡常上 。

感觉这个题挺套路的= =

首先子序列计数一定是要尽量往前选 然后考虑到ai相同不能冲突所以就是从last[a[i]]~i-1转移过来 那么显然这个就是二维前缀和优化了

第二个套路没想到 有点菜

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 5001
#define mdn 998244353
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=(s<<)+(s<<)+ch-'',ch=getchar();
return f*s;
}
int f[][N][N],pr[][N][N],pa[N],pb[N],a[N],b[N],n,m,sa[N],sb[N]; // 0 f 1 g 2 h
int query(int s,int xl,int xr,int yl,int yr){return ((ll)pr[s][xr][yr]-(xl?pr[s][xl-][yr]:)-(yl?pr[s][xr][yl-]:)+((xl&&yl)?pr[s][xl-][yl-]:)+mdn+mdn)%mdn;}
void upd(int s,int x,int y){pr[s][x][y]=((ll)pr[s][x][y-]+pr[s][x-][y]+f[s][x][y]-pr[s][x-][y-]+mdn)%mdn;}
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
int main()
{
n=read(),m=read();
for(int i=;i<=n;i++) a[i]=read(),pa[i]=sa[a[i]],sa[a[i]]=i;
for(int i=;i<=m;i++) b[i]=read(),pb[i]=sb[b[i]],sb[b[i]]=i;
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
f[][i][j]=query(,pa[i],i-,j-,j-),upd(f[][i][j],(j==&&!pa[i])),upd(,i,j);
for(int i=;i<=m;i++) for(int j=;j<=m;j++)
f[][i][j]=query(,pb[i],i-,j-,j-),upd(f[][i][j],(j==&&!pb[i])),upd(,i,j);
int ans=;
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
upd(ans,1ll*f[][i][j]*pr[][m][min(m,j-)]%mdn);
memset(f[],,sizeof(f[])); memset(f[],,sizeof(f[]));
memset(pr[],,sizeof(pr[])); memset(pr[],,sizeof(pr[]));
for(int i=;i<=n;i++) for(int j=;j<=m;j++)
{
if(a[i]==b[j]) f[][i][j]=query(,pa[i],i-,pb[j],j-),upd(f[][i][j],(!pa[i]&&!pb[j]));
if(a[i]>b[j]) f[][i][j]=query(,pa[i],i-,pb[j],j-),upd(f[][i][j],(!pa[i]&&!pb[j]));
upd(,i,j);
}
reverse(a+,a+n+); reverse(b+,b+m+);
memset(sa,,sizeof(sa)); memset(sb,,sizeof(sb));
for(int i=;i<=n;i++) pa[i]=sa[a[i]],sa[a[i]]=i;
for(int i=;i<=m;i++) pb[i]=sb[b[i]],sb[b[i]]=i;
for(int i=;i<=n;i++) for(int j=;j<=m;j++)
f[][i][j]=query(,pa[i],i-,pb[j],j-),upd(f[][i][j],(!pa[i]&&!pb[j])),upd(,i,j);
for(int i=;i<=n;i++) for(int j=;j<=m;j++)
upd(ans,1ll*f[][i][j]*(pr[][n-i][m-j]+)%mdn);
printf("%d\n",ans);
return ;
}

C

七。

A.(ZROI972)

一眼题(?

考虑到一些区间被扔到另一边不能有交的话那么就是说每一段被覆盖的次数不超过2。

连续的一段对应着两种划分,所以直接拿堆维护右端点就好了。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define inf 20021225
#define mdn 998244353
#define N 1001000
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
struct seg{int l,r;}t[N];
bool operator<(seg a,seg b){return a.l==b.l?a.r<b.r:a.l<b.l;}
priority_queue< int , vector<int> , greater <int> > q;
int main()
{
int n=read();
for(int i=;i<=n;i++) t[i].l=read(),t[i].r=read();
sort(t+,t+n+); int ans=,tmp=;
for(int i=;i<=n;i++)
{
while(!q.empty()&&q.top()<=t[i].l)
q.pop(),tmp--;
if(q.empty()) ans=(ans<<)%mdn;
q.push(t[i].r); tmp++; if(tmp>){ans=; break;}
}
printf("%d\n",ans);
return ;
}

A

B.(ZROI973)

咳咳场上写了一堆锅还好拍出来修掉了。

考虑直接dp $f(x) = min(f(\lceil \frac{x}{k+1} \rceil) + ak + b)$

显然可以直接把b减去a这样的话统一k和k+1比较方便。

然后一个显然的转化我们要$min(a \sum k_i + mb)$ 其中 $\lceil \frac{n}{\prod k_i} \rceil = 1$

显然每次除以n^(1/x)是最优的,当然有些地方要调整+1

这个只有log级别,所以最后复杂度是O(Tlg^2n)?

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
int n,a,b;
bool check(ll bs,int mi)
{
ll ans=;
while(mi)
{
if(mi&)
{
ans=ans*bs; if(ans>=n) return ;
}
bs=bs*bs; if(bs>=n && mi>) return ; mi>>=;
}
return ;
}
int get(int l,int r,int mi)
{
int ans=;
while(l<=r)
{
int mid=l+r>>;
if(check(mid,mi)) r=mid-,ans=mid;
else l=mid+;
}
return ans;
}
ll solve()
{
b=b-a;
ll tmp=,ans=b+1ll*a*n; int l=,r=n;
for(int i=;tmp<=n*;i++,tmp*=)
{
r=get(l,r,i); ll pw=;// printf("%d %d\n",r,i);
for(int j=;j<i;j++) pw*=r;
if(pw==n) ans=min(ans,1ll*a*r*i+1ll*b*i);
else
{
ll k=r*i;
for(int j=;j<i&&pw>=n;j++)
ans=min(ans,1ll*b*i+1ll*a*k),k--,pw=pw/r*(r-);
}
}
return ans;
}
int main()
{
int T=read();
while(T--)
{
n=read(),b=read(),a=read();
if(n==){puts(""); continue;}
printf("%lld\n",solve());
}
return ;
}

B

C.(ZROI974)

有点神仙的题,首先可以想到转化,一定是欧式距离再加一段反复横跳。

但是可能反复横跳的位置不在矩形内,所以需要讨论。接着考虑把它写成斜率形式(具体看题解吧)

然后维护凸包/李超树就,我写的凸包形式,最后在凸包上二分找到答案就好了。(跑的奇慢无比= =)

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 100010
#define LG 18
#define bint __int128
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=(s<<)+(s<<)+ch-'',ch=getchar();
return f*s;
}
struct ST
{
ll f[N][LG]; int lg[N];
void init(ll *a,int n)
{
for(int i=;i<=n;i++) f[i][]=a[i],lg[i]=(i==)?:lg[i>>]+;
for(int i=;i<LG;i++) for(int j=;j+(<<i)<=n;j++)
f[j][i]=min(f[j][i-],f[j+(<<i-)][i-]);
}
ll query(int l,int r)
{
int k=lg[r-l+]; return min(f[l][k],f[r-(<<k)+][k]);
}
}sx,sy;
struct poi
{
ll x,y;
poi(){}
poi(ll _x,ll _y){x=_x,y=_y;}
};
bool operator<(poi a,poi b){return a.x==b.x?a.y<b.y:a.x<b.x;}
poi operator-(poi a,poi b){return poi(a.x-b.x,a.y-b.y);}
bint cross(poi a,poi b){return (bint)a.x*b.y-(bint)a.y*b.x;}
ll calc(poi a,ll x){return x*a.x+a.y;}
#define vec vector<poi>
#define ls x<<1
#define rs x<<1|1
#define pb push_back
#define bp pop_back
struct SGT
{
vec t[N<<],tmp; int n;
void pushup(int x,int l,int r,ll *a,ll *pre,int id)
{
tmp.clear();
for(int i=l;i<=r;i++)
if(id) tmp.pb(poi(a[i],2ll*pre[i-]-2ll*i*a[i]));
else tmp.pb(poi(a[i],-2ll*pre[i]+2ll*i*a[i]));
sort(tmp.begin(),tmp.end());
for(int i=;i<tmp.size();i++)
{
while(t[x].size()> && cross(tmp[i]-t[x][t[x].size()-],t[x][t[x].size()-]-t[x][t[x].size()-])>=)
t[x].bp();
t[x].pb(tmp[i]);
}
}
void build(int x,int l,int r,ll *a,ll *pre,int id)
{
pushup(x,l,r,a,pre,id); if(l==r) return; int mid=l+r>>;
build(ls,l,mid,a,pre,id); build(rs,mid+,r,a,pre,id);
}
ll get(vec v,ll x)
{
int l=,r=v.size(); ll ans=1e18; r--;
while(l<=r)
{
if(r-l<=){for(int i=l;i<=r;i++) ans=min(ans,calc(v[i],x)); break;}
int mid=l+r>>; ll qwq=calc(v[mid],x),qaq=calc(v[mid+],x);
if (qwq<qaq) r=mid; else l=mid+;
}
return ans;
}
ll query(int x,int l,int r,int LL,int RR,ll pos)
{
if(RR<LL) return 1e18;
if(LL<=l&&RR>=r) return get(t[x],pos);
ll ans=1e18; int mid=l+r>>;
if(LL<=mid) ans=min(ans,query(ls,l,mid,LL,RR,pos));
if(RR>mid) ans=min(ans,query(rs,mid+,r,LL,RR,pos));
return ans;
}
}pa,pb,sa,sb;
ll prea[N],preb[N],a[N],b[N],rema[N],remb[N];
int n,m,q;
int main()
{
n=read(),m=read(),q=read();
for(int i=;i<n;i++) a[i]=read(),prea[i]=prea[i-]+a[i];
for(int i=;i<m;i++) b[i]=read(),preb[i]=preb[i-]+b[i];
sx.init(a,n); sy.init(b,m);
pa.build(,,n,a,prea,);pb.build(,,m,b,preb,);
sa.build(,,n,a,prea,);sb.build(,,m,b,preb,);
while(q--)
{
int x1=read(),y1=read(),x2=read(),y2=read(); ll ans=1e18;
if(x1>x2) swap(x1,x2); if(y1>y2) swap(y1,y2);
if(abs(abs(x2-x1)-abs(y2-y1))<=)
ans=prea[x2-]-prea[x1-]+preb[y2-]-preb[y1-];
else if(x2-x1>y2-y1)
{
ll len=prea[x2-]-prea[x1-]+preb[y2-]-preb[y1-]; int t=((x2-x1)-(y2-y1))>>;
if(y1!=y2) ans=len+2ll*t*sy.query(y1,y2-);
ans=min(ans,pb.query(,,m,y2,min(m-,t+y2),*(t+y2))+(-*preb[y2-]+len));
ans=min(ans,sb.query(,,m,max(,y1-t-),y1-,*(t-y1+))+(len+*preb[y1-]));
}
else
{
ll len=prea[x2-]-prea[x1-]+preb[y2-]-preb[y1-]; int t=((y2-y1)-(x2-x1))>>;
if(x1!=x2) ans=len+2ll*t*sx.query(x1,x2-);
ans=min(ans,pa.query(,,n,x2,min(n-,t+x2),*(t+x2))+(-*prea[x2-]+len));
ans=min(ans,sa.query(,,n,max(,x1-t-),x1-,*(t-x1+))+(len+*prea[x1-]));
}
printf("%lld\n",ans);
}
return ;
}

C

八。

第一场掉分呜呜呜。

无脑莽T3不打暴力太亏了,以后还是好好暴力吧(哭

A.(ZROI975)

一眼题,欧拉公式V+F-E=2即可。也可以直接维护qwq

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#define ll long long
#define inf 20021225
#define pa pair<int,int>
#define ppa pair<pa,pa>
#define mp make_pair
#define N 500100
#define fs first
#define se second
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
map<pa,bool> poi;
map<ppa,bool> edg;
char ch[N];
int main()
{
scanf("%s",ch+); pa pos=mp(,); poi[pos]=; int n=strlen(ch+);
int ans=;
for(int i=;i<=n;i++)
{
pa tmp=pos;
if(ch[i]=='L') tmp.fs--;
else if(ch[i]=='R') tmp.fs++;
else if(ch[i]=='U') tmp.se++;
else if(ch[i]=='D') tmp.se--;
if(poi[tmp]&&!edg[mp(pos,tmp)]) ans++;
poi[tmp]=; edg[mp(pos,tmp)]=edg[mp(tmp,pos)]=;
pos=tmp;
}
printf("%d\n",ans+);
return ;
}

A

B.(ZROI976)

我的计数dp水平太菜了呜呜呜。

考虑f[i][s]其中s是压位表示这个串中以s的第i位结尾是否ok,然后预处理转移即可。

发现随机数据,所以有效状态不多,直接压进map就做完了= =

//Love and Freedom.
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
#define inf 20021225
#define N 101
#define mdn 1000000007
#define IT map<ll,int>::iterator
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
map<ll,int> f[N];
ll g[][N][];
char s[N],t[N];
int sn,tn;
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
int main()
{
scanf("%s%s",s,t); sn=strlen(s),tn=strlen(t);
for(int i=;i<sn+tn;i++) for(int b=;b<;b++)
{
for(int j=;j<=tn;j++) if(i-j>=&&i-j<sn&&s[i-j]-''==b)
g[][i][b]|=1ll<<j;
for(int j=;j<tn;j++) if(t[j]-''==b)
g[][i][b]|=1ll<<j;
}
f[][]=;
for(int i=;i<sn+tn;i++)
{
IT it=f[i].begin();
while(it!=f[i].end())
{
ll st=(*it).first; int v=(*it).second;
for(int b=;b<;b++)
upd(f[i+][(g[][i][b]&st)|((g[][i][b]&st)<<)],v);
it++;
}
}
printf("%d\n",f[sn+tn][1ll<<tn]);
return ;
}

B

C.(ZROI977)

无脑莽了1h(别问我中间干嘛去了,太累了拖肥去了。。)

做法很科学,就是多了一个鸽笼原理,如果有多于2n个点,所有点都可以了。

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define inf 20021225
#define N 2100
#define mp make_pair
#define fs first
#define se second
#define pa pair<int,int>
#define pb push_back
using namespace std;
int read()
{
int s=,t=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') t=-; ch=getchar();}
while(ch>='' && ch<='') s=s*+ch-'',ch=getchar();
return s*t;
}
int tagh[N][N],tags[N][N],tagl[N][N],tagr[N][N];
int tagld[N][N],taglu[N][N],tagru[N][N],tagrd[N][N],s[N][N];
bool a[N][N],ok[N][N];
vector<pa> poi; int n;
int main()
{
n=read();
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
{
a[i][j]=read(); if(a[i][j]) poi.pb(mp(i,j));
}
if(poi.size()>(n<<))
{
for(int i=;i<=n;i++,puts("")) for(int j=;j<=n;j++)
printf("Y ");
return ;
}
for(int i=;i<poi.size();i++) for(int j=i+;j<poi.size();j++)
{
pa p1=min(poi[i],poi[j]),p2=max(poi[i],poi[j]);
if(p1.fs==p2.fs)
{
int det=p2.se-p1.se,d=det>>; if(det&) continue;
tags[][p1.se+d]++;
}
else if(p1.se==p2.se)
{
int det=p2.fs-p1.fs,d=det>>; if(det&) continue;
tagh[p1.fs+d][]++;
}
else if(p1.se<p2.se)
{
int det=p2.se-p1.se+p2.fs-p1.fs; if(det&) continue;
int d=det>>,w=p1.fs+p1.se+d;
if(p1.fs-p2.fs==p1.se-p2.se)
tagl[p1.fs][w-p1.fs]++,tagld[p2.fs][p1.se]=,tagru[p1.fs][p2.se]=;
else
{
if(p2.se-p1.se>d)
{
int y=w-p1.fs,_y=w-p2.fs-;
tagl[p1.fs][y]++;
tagl[p2.fs+][_y]--;
tags[][y]++;
tags[p1.fs+][y]--; tags[p2.fs][_y+]++;
}
else
{
int x=w-p1.se,_x=w-p2.se-;
tagl[_x+][p2.se]++;
tagl[x][p1.se]--; tagh[x][]++;
tagh[x][p1.se+]--; tagh[_x+][p2.se]++;
}
}
}
else
{
int det=p1.se-p2.se+p2.fs-p1.fs; if(det&) continue;
int d=det>>,w=p2.fs-p2.se-d;
if(p1.fs+p1.se==p2.fs+p2.se)
tagr[p1.fs][p1.fs-w]++,taglu[p1.fs][p2.se]=,tagrd[p2.fs][p1.se]=;
else
{
if(p1.se-p2.se>d)
{
int y=p1.fs-w,_y=p2.fs+-w;
tagr[p1.fs][y]++;
tagr[p2.fs+][_y]--; tags[][y]++;
tags[p1.fs+][y]--; tags[p2.fs][_y-]++;
}
else
{
int x=p2.se+w,_x=p1.se++w;
tagr[x][p2.se]++;
tagr[_x-][p1.se]--; tagh[x][]++;
tagh[x][p2.se+]--; tagh[_x-][p1.se]++;
}
}
}
} for(int i=;i<=n;i++) for(int j=;j<=n;j++)
tagrd[i][j]|=tagrd[i-][j]|tagrd[i][j-],
ok[i][j]|=tagrd[i][j];
for(int i=;i<=n;i++) for(int j=n;j;j--)
tagld[i][j]|=tagld[i-][j]|tagld[i][j+],
ok[i][j]|=tagld[i][j];
for(int i=n;i;i--) for(int j=;j<=n;j++)
tagru[i][j]|=tagru[i+][j]|tagru[i][j-],
ok[i][j]|=tagru[i][j];
for(int i=n;i;i--) for(int j=n;j;j--)
taglu[i][j]|=taglu[i+][j]|taglu[i][j+],
ok[i][j]|=taglu[i][j];
for(int i=;i<=n;i++) for(int j=,tmp=;j<=n;j++)
tmp+=tagh[i][j],ok[i][j]|=(bool)(tmp);
for(int j=;j<=n;j++) for(int i=,tmp=;i<=n;i++)
tmp+=tags[i][j],ok[i][j]|=(bool)(tmp);
for(int i=;i<=n;i++) for(int j=n;j;j--)
s[i][j]=s[i-][j+]+tagl[i][j],ok[i][j]|=s[i][j];
memset(s,,sizeof(s));
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
s[i][j]=s[i-][j-]+tagr[i][j],ok[i][j]|=s[i][j];
memset(s,,sizeof(s));
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
s[i][j]=s[i-][j]+tags[i][j],ok[i][j]|=s[i][j];
memset(s,,sizeof(s));
for(int i=;i<=n;i++) for(int j=;j<=n;j++)
s[i][j]=s[i][j-]+tagh[i][j],ok[i][j]|=s[i][j];
for(int i=;i<=n;i++,puts("")) for(int j=;j<=n;j++)
printf("%c ",(ok[i][j])?'Y':'N');
return ;
}

C

ZROI2019 提高十连测的更多相关文章

  1. 提高十连测day3

    提高十连测day3 A 我们可以枚举两个 $ 1 $ 之间的相隔距离,然后计算形如 $ 00100100 \cdots $ 的串在原串中最⻓⼦序列匹配即可,复杂度 $ O(n^2) $ .寻找 $ S ...

  2. ZROI 提高十连测 Day1

    第一天的提高模拟测 考前特意睡了20min 还是歇菜了,果然自己菜是真实的. 题目质量海星 但是我都不会这是真的...题目由于是花钱买的这里就不放了 LINK:problem 熟悉我的人应该都知道账号 ...

  3. ZROI 提高十连测 DAY3

    由于我不太会写 觉得从比赛开始就冷静分析.然后看完三道题心态有点爆炸没有紧扣题目的性质. 这个心态是不可取的尽量不要有畏难心理 不要草草的写暴力. LINK:[最长01子序列](http://zhen ...

  4. ZROI 提高十连测 DAY2

    总结:入题尽量快,想到做法要先证明是否正确是否有不合法的情况,是否和题目中描述的情景一模一样.    不要慌 反正慌也拿不了多少分,多分析题目的性质如果不把题目的性质分析出来的话,暴力也非常的难写,有 ...

  5. bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树

    [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 93  Solved: 53[Submit][Status][ ...

  6. bzoj 5216: [Lydsy2017省队十连测]公路建设

    5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 66  Solved: 37[Submit][St ...

  7. Lydsy2017省队十连测

    5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...

  8. 正睿 2018 提高组十连测 Day4 T3 碳

    记'1'为+1,'0'为-1; 可以发现 pre[i],suf[i]分别为前/后缀和 a[i]=max(pre[l.....i]); b[i]=max(suf[i+1....r]); ans=max( ...

  9. 正睿 2018 提高组十连测 Day2 T2 B

    题目链接 http://www.zhengruioi.com/contest/84/problem/318 题解写的比较清楚,直接扒过来了. B 算法 1 直接按题意枚举,动态规划或是记忆化搜索. 时 ...

随机推荐

  1. 【转】C++ 模板类的声明与实现分离问题

    链接如下: https://www.cnblogs.com/tonychen-tobeTopCoder/p/5199655.html

  2. win10 安装了virtualBox 启动报错 rc=-5640

    刚刚安装的virtualbox 启动就弹窗报错,,但是通过找到log 发现了下面这样的一处报错: 然后搜素发现是跟win10应用程序错误,,解决办法如下: 1.到控制面板,,--程序 再次尝试,vir ...

  3. 构建嵌入式Linux交叉编译工具链

    开源交叉编译工具链制作方法汇总: 1) 使用crosstool/crosstool-ng生成 2) 使用buildroot生成 ARM交叉编译工具链说明: 1) arm-linux-gcc是一个集合命 ...

  4. PROD异机全备份恢复验证实施文档

    PROD异机全备份恢复验证实施文档 ******利用10月25日的全量备份.10月26日当天的归档日志及当前redo日志,恢复数据库到故障前数据库状态****** 准备工作:source 源库:PRO ...

  5. Hbase——HA搭建

    架构 master1,2 免秘钥登录 配置环境变量export HBASE_HOME=/root/hbase-0.99.2export PATH=$PATH:$HBASE_HOME/bin 修改配置文 ...

  6. Delphi XE2 之 FireMonkey 入门(3) - 关于 TPosition

    把 FireMonkey 简称为 FM 吧. FM 的窗体继续使用 Left.Top 属性, 但更多控件不是了. //FM 控件的位置控制不再是 Left.Top, 取而代之的是 Position 属 ...

  7. tcp中的常见定时器

    (1)超时重传定时器tcp的靠谱特性,通过确认机制,保证每一个包都被对方收到,那么什么时候需要重传呢?就是靠这个超时重传定时器,每次发送报文前都启动这个定时器,如果定时器超时之前收到了应答则关闭定时器 ...

  8. C# datatable 与 xml文件之间的转换

    /// <summary> /// datatable转XML文件 /// </summary> /// <param name="dtTable"& ...

  9. Python解决NameError: name 'reload' is not defined的问题

    遇到这个问题,对于 Python 2.X: import sys reload(sys) sys.setdefaultencoding("utf-8") 对于 Python 3.3 ...

  10. layui的分页使用(前端分页)

    <div id="one"></div>//显示数据库中数据的<ul id="ones"></ul>//显示分页 ...