A. Donut

扫描线+线段树。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=800010,M=2222222;
int n,m,cnt,i,j;ll L,R,D,a[N];
int tag[M],v[M],ans;
struct E{
ll x,l,r;int s;
E(){}
E(ll _x,ll _l,ll _r,int _s){x=_x,l=_l,r=_r,s=_s;}
}e[N];
inline bool cmp(const E&a,const E&b){return a.x<b.x;}
inline void tag1(int x,int p){tag[x]+=p;v[x]+=p;}
void add(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){
tag1(x,p);
return;
}
if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;
int mid=(a+b)>>1;
if(c<=mid)add(x<<1,a,mid,c,d,p);
if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
v[x]=max(v[x<<1],v[x<<1|1]);
}
int main(){
scanf("%d%lld%lld",&n,&L,&R);L--;
while(n--){
ll x,y;
int s;
scanf("%lld%lld%d",&x,&y,&s);
e[++m]=E(x-R,y-R,y+R,s);
e[++m]=E(x+R+1,y-R,y+R,-s);
e[++m]=E(x-L,y-L,y+L,-s);
e[++m]=E(x+L+1,y-L,y+L,s);
}
for(i=1;i<=m;i++)a[++cnt]=e[i].l,a[++cnt]=e[i].r;
sort(a+1,a+cnt+1);
sort(e+1,e+m+1,cmp);
for(i=1;i<=m;i=j){
for(j=i;j<=m&&e[i].x==e[j].x;j++)add(1,1,cnt,lower_bound(a+1,a+cnt+1,e[j].l)-a,lower_bound(a+1,a+cnt+1,e[j].r)-a,e[j].s);
ans=max(ans,v[1]);
}
printf("%d",ans);
}

  

B. Circular Arrangement

留坑。

C. Earthquake

对于一条路径内部来说,最优策略肯定是从存在概率最小的开始询问。

对于不同路径之间来说,考虑排序不等式贪心即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
double a[N];
long double win[N], fail[N];
struct A
{
long double failp;
long double step;
bool operator < (const A & b) const
{
long double afirst = step + failp * b.step;
long double bfirst = b.step + b.failp * step;
return afirst < bfirst;
}
}v[N];
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1; i <= n; ++i)
{
int g; scanf("%d", &g);
for(int j = 1; j <= g; ++j)
{
scanf("%lf", &a[j]);
a[j] /= 1000;
}
sort(a + 1, a + g + 1);
win[0] = 1;
fail[0] = 0;
v[i].step = 0;
for(int j = 1; j <= g; ++j)
{
win[j] = win[j - 1] * a[j];
fail[j] = fail[j - 1] + win[j - 1] * (1 - a[j]);
v[i].step += win[j - 1] * (1 - a[j]) * j;
}
v[i].step += win[g] * g;
v[i].failp = fail[g];
}
sort(v + 1, v + n + 1);
long double ans = 0;
long double p = 1;
for(int i = 1; i <= n; ++i)
{
ans += p * v[i].step;
p *= v[i].failp;
}
printf("%.12f\n", (double)ans);
}
return 0;
} /*
【trick&&吐槽】
2
3 900 900 900
2 100 100 3
1 240
1 310
1 50 【题意】 【分析】 【时间复杂度&&优化】 */

  

D. Dynamic Input Tool

贪心,若不是子序列则进行一次操作。

#include<cstdio>
#include<cstring>
const int N=1000010;
int n,i,j,f[N][26];
int l,r,x,ans;
int vis[26];
char a[N];
int main(){
scanf("%s",a+1);
n=strlen(a+1);
for(i=1;i<=n;i++)a[i]-='a';
for(j=0;j<26;j++)f[n+1][j]=n+1;
for(i=n;i;i--){
for(j=0;j<26;j++)f[i][j]=f[i+1][j];
f[i][a[i]]=i;
}
for(i=1;i<=n;i++){
if(!vis[a[i]]){
if(l&&l<i)ans++;
vis[a[i]]=1;
ans++;
l=i+1;
x=1;
}else{
x=f[x][a[i]];
if(x>=l){
ans++;
x=f[1][a[i]];
l=i;
}
x++;
}
}
if(l<=n)ans++;
printf("%d",ans);
}

  

E. Central Lake

答案即为圆周上距离最远的两个点的距离,求出两个点后可以求切线得出答案。

对于求最远点对,可以使用set支持插入操作,对于删除则按时间分治即可。

时间复杂度$O(n\log^2n)$。

#define ms(x, y) memset(x, y, sizeof(x))
#define mc(x, y) memcpy(x, y, sizeof(x))
#define mid (l+r>>1)
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
#define ls o << 1
#define rs o << 1 | 1
#define rt 1,1,Q+1
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<list>
#include<set>
#include<string>
#include<algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
template <class T> inline void gmax(T &a, T b){if(b > a) a = b;}
template <class T> inline void gmin(T &a, T b){if(b < a) a = b;}
using namespace std;
const int N = 4e5 + 10, M = 1e6 + 10, Z = 1e9 + 7, maxint = 2147483647, ms1 = 16843009, ms31 = 522133279, ms63 = 1061109567, ms127 = 2139062143;
const double PI = acos(-1.0), eps = 1e-8;
double R, r;
int n;
int LL, RR, X;
vector<int> w[N], v[N * 4];
int a[N]; /*
const int BS = 360000;
struct point{
long double x, y, z;
point(){}
point (long double x_,long double y_,long double z_=1.0){x=x_,y=y_,z=z_;}
point operator -(const point &p)const{
return {x-p.x,y-p.y};
}
point operator +(const point &p)const{
return {x+p.x,y+p.y};
}
point operator *(const long double &k)const{
return {x*k,y*k};
}
long double Norm(){
return sqrtl(x*x+y*y);
}
point Rotate(const long double &AA)const{
long double c = cosl(AA);
long double s = sinl(AA);
return {c*x-s*y, x*s+c*y};
}
}O;
point Seg(point a, point b){
return {b.y-a.y,a.x-b.x,-a.x*b.y+a.y*b.x};
}
long double val(int d){
long double AA = (long double)d/BS * 2*PI;
point p = {(long double)R, (long double)0};
point q = {R*cosl(AA), R*sinl(AA)};
point S = Seg(p,q);
long double dis = S.z/sqrtl(S.x*S.x+S.y*S.y);
if(dis<0)dis=-dis;
if(dis > r){
return (q-p).Norm();
}
long double BB = asinl((long double)r/R);
point v1 = (O-q).Rotate(BB);
long double dd = sqrtl((long double)R*R-(long double)r*r);
v1 = q + v1*((long double)1.0/v1.Norm()*dd);
point v2 = (O-p).Rotate(-BB);
v2 = p + v2*((long double)1.0/v2.Norm()*dd);
return (q-v1).Norm() + (p-v2).Norm() + (atan2l(v1.y,v1.x) - atan2l(v2.y,v2.x))*r;
}
*/ struct Point
{
double x, y;
Point(double x_, double y_){ x = x_; y = y_; }
friend Point operator - (const Point &a, const Point &b){
return Point(a.x - b.x, a.y - b.y);
}
friend Point operator + (const Point &a, const Point &b){
return Point(a.x + b.x, a.y + b.y);
}
friend Point operator * (const Point &a, const double &b){
return Point(a.x * b, a.y * b);
}
friend Point operator / (const Point &a, const double &b){
return Point(a.x / b, a.y / b);
}
double len2(){
return x * x + y * y;
}
double len()
{
return sqrt(len2());
}
Point rotate(const double ang){
return Point(cos(ang) * x - sin(ang) * y, cos(ang) * y + sin(ang) * x);
}
Point turn90(){
return Point(-y, x);
}
};
struct Circle
{
Point o;
double r;
Circle(Point o = Point(0, 0), double r = 0) : o(o), r(r) {}
}; vector<Point> circleTangentPoint(const Circle &c, const Point &p0)
{
double x = (p0 - c.o).len2(), r = c.r;
double d = x - r * r;
vector<Point> ret;
if(d < -eps){
return ret;
}
if(d < 0){
d = 0;
}
Point p = (p0 - c.o) * (r * r / x), delta = ((p0 - c.o) * (-r * sqrt(d) / x)).turn90();
ret.push_back(c.o + p + delta);
ret.push_back(c.o + p - delta);
return ret;
} double TH(double x)
{
return x * PI / 180;
} int sgn(double x)
{
if(fabs(x) < eps) return 0;
return x > 0 ? 1 : -1;
}
double L(Point aa, Point bb)
{
if(sgn((aa - bb).len2() - 4.0 * r * r) == 0){
return PI * r;
}
Point cc = {0, 0};
double a = (bb - cc).len(), b = (aa - cc).len(), c = (aa - bb).len();
double cosc = (b * b + a * a - c * c) / (2 * a * b);
double th = acos(cosc);
return th * r;
} double val(int n)
{
//printf("%d\n", n);
Point o = {0, 0};
Point p = {0, -R}; Point pp = p;
p = p.rotate(TH(1.0 * n / 1000));
double dist = (pp - p).len();
if(dist <= sqrt(R * R - r * r) * 2){
return dist;
}
Circle c; c.o = {0, 0}; c.r = r;
vector<Point> inter = circleTangentPoint(c, p);
vector<Point> origi = circleTangentPoint(c, pp);
Point p1 = inter[0], p2 = inter[1], p3 = origi[0], p4 = origi[1];
double ans = min(min(L(p1, p3), L(p1, p4)), min(L(p2, p3), L(p2, p4)));
return ans + 2 * (p - p1).len();
} void build(int o, int l, int r)
{
v[o].clear();
if(l == r)return;
build(lson);
build(rson);
}
void update(int o, int l, int r)
{
if(LL <= l && r <= RR)
{
v[o].push_back(X);
return;
}
if(LL <= mid)update(lson);
if(RR > mid)update(rson);
}
set<int>sot;
const int A = 360000;
const int H = 180000;
double ans[N];
int minn(int x)
{
if(x<0)x=-x;
x %= A;
x += A;
x %= A;
return min(x, A - x);
}
void solve(int o, int l, int r, int maxD)
{
for(auto x : v[o])
{
set<int>::iterator it = sot.lower_bound(x + H);
if(it != sot.end())gmax(maxD, minn(x + A - *it));
if(it != sot.begin())gmax(maxD, minn(*(--it) - x));
sot.insert(x);
sot.insert(x + A);
}
if(l == r)
{
ans[l] = val(maxD);
}
else
{
solve(lson, maxD);
solve(rson, maxD);
}
for(auto x : v[o])
{
sot.erase(x);
sot.erase(x + A);
}
v[o].clear();
}
int main()
{
while(~scanf("%lf%lf", &R, &r))
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
w[a[i]].push_back(1);
}
int Q;
scanf("%d", &Q);
build(rt);
for(int i = 1; i <= Q; ++i)
{
int op, x;
scanf("%d%d", &op, &x);
w[x].push_back(i + 1);
}
for(int i = 0; i < 360000; ++i)
{
X = i;
for(int j = 0; j < w[i].size(); j += 2)
{
LL = w[i][j];
if(j == w[i].size() - 1)RR = Q + 1;
else RR = w[i][j + 1] - 1;
update(rt);
}
w[i].clear();
}
solve(rt, 0);
for(int i = 1; i <= Q + 1; ++i)printf("%.10f\n", ans[i]);
}
return 0;
} /* 题意:
10 5
2
0 90000
4
1 180000
1 240000
2 0
2 90000 类型: 分析: 优化: trick: 数据: Sample Input Sample Output */

  

F. Computing MDSST

设$f[S][i]$表示$S$集合的点形成一棵树,根为$i$的最小代价,枚举补集的子集转移。

时间复杂度$O(3^nn^2)$。

#include<cstdio>
typedef long long ll;
const int N=15;
const ll inf=1LL<<60;
int n,i,j,S,U,T,c[1<<N],g[N][N];ll f[1<<N][N];
inline void up(ll&a,ll b){a>b?(a=b):0;}
int main(){
scanf("%d",&n);
for(i=0;i<n;i++)for(j=i+1;j<n;j++){
scanf("%d",&g[i][j]);
g[j][i]=g[i][j];
}
for(S=0;S<1<<n;S++)for(i=0;i<n;i++)f[S][i]=inf;
for(i=0;i<1<<n;i++)c[i]=__builtin_popcount(i);
for(i=0;i<n;i++)f[1<<i][i]=0;
for(S=0;S<1<<n;S++)for(i=0;i<n;i++)if(S>>i&1){
for(j=0;j<n;j++)if(j!=i&&(S>>j&1)){
T=S^(1<<i)^(1<<j);
for(U=T;;U=(U-1)&T){
up(f[S][i],f[(T-U)|(1<<i)][i]+f[U|(1<<j)][j]+1LL*g[i][j]*(c[U]+1)*(n-c[U]-1));
if(!U)break;
}
}
}
for(i=1;i<n;i++)up(f[(1<<n)-1][0],f[(1<<n)-1][i]);
printf("%lld",f[(1<<n)-1][0]);
}

  

G. MST with Metropolis

首先求出最小生成树,那么对于每个点可以看成加入$deg_i$条边权为$0$的边,LCT维护即可。

时间复杂度$O(m\log m)$。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1000000;
struct edge{int x,y,a;}e[N];
bool cmp(const edge&a,const edge&b){return a.a<b.a;}
int n,m,i,j,fa[N];
int f[N],son[N][2],val[N],sum[N],from[N],tmp[N];bool rev[N];
vector<int>vg[N];
ll all;
int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
inline bool isroot(int x){return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x);}
inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
inline void up(int x){
sum[x]=val[x],from[x]=x;
if(son[x][0])if(sum[son[x][0]]>sum[x])sum[x]=sum[son[x][0]],from[x]=from[son[x][0]];
if(son[x][1])if(sum[son[x][1]]>sum[x])sum[x]=sum[son[x][1]],from[x]=from[son[x][1]];
}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
}
inline void splay(int x){
int s=1,i=x,y;tmp[1]=i;
while(!isroot(i))tmp[++s]=i=f[i];
while(s)pb(tmp[s--]);
while(!isroot(x)){
y=f[x];
if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(x);
}
inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
inline void makeroot(int x){access(x);splay(x);rev1(x);}
inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}
inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
inline void cut(int x,int y){makeroot(x);cutf(y);}
inline int askfrom(int x,int y){makeroot(x);access(y);splay(y);return from[y];}
inline ll solve(int x){
ll sum=0;
vector<int>v;
for(int i=0;i<vg[x].size();i++){
int k=vg[x][i];
sum+=e[k].a;
int A=x,B=e[k].x+e[k].y-A;
int j=askfrom(A,B);
sum-=e[j-n].a;
v.push_back(j);
cut(j,e[j-n].x),cut(j,e[j-n].y);
link(A,n+m+k),link(B,n+m+k);
}
for(int i=0;i<vg[x].size();i++){
int k=vg[x][i];
int A=x,B=e[k].x+e[k].y-A;
cut(A,n+m+k),cut(B,n+m+k);
}
for(int i=0;i<v.size();i++){
int j=v[i];
link(j,e[j-n].x),link(j,e[j-n].y);
}
return sum+all;
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].a);
sort(e+1,e+m+1,cmp);
for(i=1;i<=n;i++)fa[i]=i,val[i]=-1,from[i]=i;
for(i=1;i<=m;i++)val[n+i]=e[i].a,from[n+i]=n+i;
for(i=1;i<=m;i++)val[n+m+i]=0,from[n+m+i]=n+m+i;
for(i=1;i<=m;i++)if(F(e[i].x)!=F(e[i].y)){
fa[fa[e[i].x]]=fa[e[i].y];
link(e[i].x,n+i);
link(e[i].y,n+i);
all+=e[i].a;
}
for(i=1;i<=m;i++)vg[e[i].x].push_back(i),vg[e[i].y].push_back(i);
for(i=1;i<=n;i++)printf("%lld\n",solve(i));
}

  

H. Number of Cycles

留坑。

I. Sum of Squares of the Occurrence Counts

建立后缀自动机,设$w_i=ml_i-ml_{pre_i},v_i$表示$i$点的$right$集合大小,则$ans=\sum w_iv_i^2$。

每次加入一个新点时,需要将该点到根路径上所有$v$值加$1$,LCT打标记维护即可。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<cstring>
#define N 200010
typedef long long ll;
char s[N];int n,i;ll ans;
int tot=1,last=1,pre[N],son[N][26],ml[N];
namespace LCT{
int f[N],son[N][2],a[N];
ll tag[N];
bool rev[N];
ll w[N],v[N],sw[N],swv[N];
inline void swap(int&a,int&b){int c=a;a=b;b=c;}
inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
inline void reverse(int x){if(x)swap(son[x][0],son[x][1]),rev[x]^=1;}
inline void add(int x,ll y){
if(x){
v[x]+=y;
swv[x]+=sw[x]*y;
tag[x]+=y;
}
}
inline void up(int x){
sw[x]=w[x]+sw[son[x][0]]+sw[son[x][1]];
swv[x]=w[x]*v[x]+swv[son[x][0]]+swv[son[x][1]];
}
inline void pb(int x){
if(rev[x])reverse(son[x][0]),reverse(son[x][1]),rev[x]=0;
if(tag[x])add(son[x][0],tag[x]),add(son[x][1],tag[x]),tag[x]=0;
}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
}
inline void splay(int x){
int s=1,i=x,y;a[1]=i;
while(!isroot(i))a[++s]=i=f[i];
while(s)pb(a[s--]);
while(!isroot(x)){
y=f[x];
if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(x);
}
inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
inline void makeroot(int x){access(x);splay(x);reverse(x);}
inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}
inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
inline void cut(int x,int y){makeroot(x);cutf(y);}
inline void changew(int x,ll p){
access(x);
splay(x);
w[x]=p;
up(x);
}
inline void maketag(int x){
makeroot(1);
access(x);
splay(x);
ans+=2*swv[x]+sw[x];
add(x,1);
}
inline void copy(int y,int x){
access(x);splay(x);
w[y]=w[x];
v[y]=v[x];
up(y);
}
inline void setv(int x,int p){
w[x]=p;
up(x);
}
}
inline void add(int w){
int p=++tot,x=last,r,q;
ml[p]=ml[x]+1;last=p;
for(;x&&!son[x][w];x=pre[x])son[x][w]=p;
if(!x){
pre[p]=1;
LCT::setv(p,ml[p]-ml[pre[p]]);
LCT::link(p,pre[p]);
}else if(ml[x]+1==ml[q=son[x][w]]){
pre[p]=q;
LCT::setv(p,ml[p]-ml[pre[p]]);
LCT::link(p,pre[p]);
}else{
pre[r=++tot]=pre[q];
LCT::copy(r,q);
LCT::link(r,pre[q]);
memcpy(son[r],son[q],sizeof son[r]);
ml[r]=ml[x]+1;
LCT::cut(q,pre[q]);
LCT::link(q,r);
pre[p]=pre[q]=r;
LCT::setv(p,ml[p]-ml[pre[p]]);
LCT::link(p,r);
LCT::changew(r,ml[r]-ml[pre[r]]);
LCT::changew(q,ml[q]-ml[pre[q]]);
for(;x&&son[x][w]==q;x=pre[x])son[x][w]=r;
}
LCT::maketag(p);
}
int main(){
scanf("%s",s+1);n=strlen(s+1);
for(i=1;i<=n;i++){
add(s[i]-'a');
printf("%lld\n",ans);
}
}

  

J. Game of Sorting

对于一个区间$[l,r]$,若它是单调的,则显然先手必败。

若去掉$l$或者$r$后变成了单调的,则显然先手必胜。

若$[l+1,r-1]$是单调的,那么同理先手必败。

若$[l,r-2]$是单调的,那么先手若取$r$会导致后手必胜,后手同理,故两人会一直取$l$直到出现上面第一种或者第二种情况,可以根据奇偶性判断。

同理可以得出$[l+2,r]$是单调的情形的处理方法。

除此之外,有$[l,r]$的答案等于$[l+1,r-1]$的答案,二分找到最小的$k$满足$[l+k,r-k]$可以由上面方法直接判断出胜负即可。

时间复杂度$O(m\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000010;
int n,i,a[N],fl[N],fr[N],gl[N],gr[N],m,x,y;
inline int check(int l,int r){
if(l>=r)return -1;
if(fr[l]>=r)return -1;
if(fr[l]==r-1)return 1;
if(fl[r]==l+1)return 1;
if(fr[l+1]==r-1)return -1;
int x;
if(fr[l]==r-2){
if(fl[r-1]<fl[r])x=(l&1)^(fl[r-1]&1)^1;
else x=(l&1)^(fl[r]&1);
return x?1:-1;
}
if(fl[r]==l+2){
if(fr[l+1]>fr[l])x=(r&1)^(fr[l+1]&1)^1;
else x=(r&1)^(fr[l]&1);
return x?1:-1;
}
return 0;
}
inline int cal(int x,int y){
int l=0,r=(y-x)/2+5,mid,t,o;
while(l<=r){
mid=(l+r)>>1;
t=check(x+mid,y-mid);
if(!t)l=mid+1;else r=mid-1,o=t;
}
return o;
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(fr[n]=gr[n]=n,i=n-1;i;i--){
fr[i]=a[i]<=a[i+1]?fr[i+1]:i;
gr[i]=a[i]>=a[i+1]?gr[i+1]:i;
}
for(fl[1]=gl[1]=1,i=2;i<=n;i++){
fl[i]=a[i]<=a[i-1]?fl[i-1]:i;
gl[i]=a[i]>=a[i-1]?gl[i-1]:i;
}
for(i=1;i<=n;i++)fl[i]=min(fl[i],gl[i]),fr[i]=max(fr[i],gr[i]);
scanf("%d",&m);
while(m--)scanf("%d%d",&x,&y),puts(cal(x,y)>0?"Alice":"Bob");
}

  

K. Subsequence Queries

设$f_i$表示以字符$i$为结尾的本质不同子序列的个数,$sum$为所有本质不同子序列(包含空串)的个数,则一开始$f_i=0,sum=1$。

若往序列末尾添加一个字符$x$,则有$f_x=sum,sum=2sum-f_x$,可以将其写成转移矩阵$G_x$。

考虑将上述式子倒过来,则可以得出删除末尾字符$x$的转移,也就是$G_x^{-1}$。

则区间$[l,r]$的答案$=G_rG_{r-1}...G_{l+1}G_l=G_{r+1}^{-1}G_{r+2}^{-1}G_{n-1}^{-1}G_n^{-1}G_nG_{n-1}...G_{l+1}G_l$。

故预处理出$G$的后缀积的最后一列以及$G^{-1}$的后缀积的最后一行即可在$O(S)$的时间里求出$sum$。

对于预处理,注意到$G$和$G^{-1}$与单位矩阵$E$相比只有$4$个位置不同,故可以只考虑这$4$个位置的线性贡献在$O(S)$的时间里完成矩阵乘法。

时间复杂度$O((n+q)S)$。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i) for(int i=0;i<M;i++)
using namespace std;
const int N=1000010,M=53,P=1000000007;
int n,i,j,g[M][M],w[M][M],tmp[M],b[N][M],c[N][M];char a[N];
inline int getid(char x){
if(x>='a'&&x<='z')return x-'a';
return x-'A'+26;
}
inline void apply(int x){
//x,x,-1
//x,M-1,1
//M-1,x,-1
//M-1,M-1 1
rep(i)w[i][x]=g[i][x],w[i][M-1]=g[i][M-1];
rep(i){
(g[i][x]-=w[i][x])%=P;
(g[i][M-1]+=w[i][x])%=P;
(g[i][x]-=w[i][M-1])%=P;
(g[i][M-1]+=w[i][M-1])%=P;
}
}
inline void applyinv(int x){
rep(i)tmp[i]=g[x][i],g[x][i]=(2LL*g[x][i]-g[M-1][i])%P;
rep(i)g[M-1][i]=tmp[i];
/*newf[x]=olds
news=olds*2-oldf[x] olds=newf[x]
oldf[x]=newf[x]*2-news*/
}
inline int cal(int l,int r){
int ret=0;
rep(i)ret=(1LL*b[l][i]*c[r+1][i]+ret)%P;
return (ret+P)%P;
}
const int Base=1000000000;
int len[M+1];
int num[M+1][N];
inline void copy(int x,int y){
len[x]=len[y];
for(int i=len[x];i;i--)num[x][i]=num[y][i];
}
inline void mul2(int x){
int l=len[x],i;
num[x][++l]=0;
for(i=1;i<=l;i++)num[x][i]<<=1;
for(i=1;i<l;i++)if(num[x][i]>=Base)num[x][i+1]++,num[x][i]-=Base;
while(l>1&&!num[x][l])l--;
len[x]=l;
}
inline void sub(int x,int y){
int l=len[x],i;
for(i=len[y];i;i--)num[x][i]-=num[y][i];
for(i=1;i<l;i++)if(num[x][i]<0)num[x][i+1]--,num[x][i]+=Base;
while(l>1&&!num[x][l])l--;
len[x]=l;
}
inline void gao(int x){
copy(M,x);
copy(x,M-1);
mul2(M-1);
sub(M-1,M);
}
void write(int x){
printf("%d",num[x][len[x]]);
for(int i=len[x]-1;i;i--)printf("%09d",num[x][i]);
}
int main(){
scanf("%s",a+1);
n=strlen(a+1);
rep(i)g[i][i]=1;
rep(j)b[n+1][j]=g[j][M-1];
for(i=n;i;i--){
apply(getid(a[i]));
rep(j)b[i][j]=g[j][M-1];
}
rep(i)rep(j)g[i][j]=0;
rep(i)g[i][i]=1;
rep(j)c[n+1][j]=g[M-1][j];
for(i=n;i;i--){
applyinv(getid(a[i]));
rep(j)c[i][j]=g[M-1][j];
}
/*int x,y;
while(~scanf("%d%d",&x,&y)){
printf("%d\n",cal(x,y));
}*/
int q,a0,b0,pp,qq,rr,last=0;
int L,R;
scanf("%d%d%d%d%d%d",&q,&a0,&b0,&pp,&qq,&rr);
while(q--){
int na=(1LL*pp*a0+1LL*qq*b0+last+rr)%P;
int nb=(1LL*pp*b0+1LL*qq*a0+last+rr)%P;
int x=min(na%n+1,nb%n+1);
int y=max(na%n+1,nb%n+1);
L=x,R=y;
last=cal(x,y);
a0=na,b0=nb;
}
printf("%d",last);
return 0;
rep(i)len[i]=1;
num[M-1][1]=1;
for(i=L;i<=R;i++)gao(getid(a[i]));
write(M-1);
}
/*
aadhuihGDSTYFSJHJUYFRgdgjesfgAGFDHSFHDTedsjydaJdgHSdfhyjFhsGvfhdzgfjsfjySfgyjhzdfgjzdfgjzfgjhdfgjGfyjhzdgfzjyfgzdjhgfdjdfdfdfdfdfdfdfdfdffdfdfzgjSGHFDsyJHFGhGFujyFGTjySFyJGDjSdgjyhSFhgZFGjhSDF
100 100 245 463 356 234243
85192723079788 */

  

L. XOR Transformation

将$T$二进制拆分,将每个$1$拿出来单独做$2^t$步操作。

对于$2^t$步操作,每个点的值会变成往后$2^t$一步$k$个点的异或和,将$k$模以两倍的环长后用前缀异或和计算即可。

时间复杂度$O(n\log T)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=222222;
int n,m,i,a[N];ll T;
int v[N],q[N],b[N];
void solve(int k){
ll t=1LL<<k;
t%=n;
int i,j;
for(i=0;i<n;i++)v[i]=0;
for(i=0;i<n;i++)if(!v[i]){
int len=0;
for(j=i;!v[j];j=(j+t)%n)v[q[len++]=j]=1;
for(j=0;j<len;j++)b[j]=b[j+len]=a[q[j]];
for(j=1;j<len+len;j++)b[j]^=b[j-1];
for(j=0;j<len;j++){
int val=b[((j+m-1)%(len*2)+len*2)%(len*2)];
if(j)val^=b[j-1];
a[q[j]]=val;
}
}
}
int main(){
scanf("%d%d%lld",&n,&m,&T);
for(i=0;i<n;i++)scanf("%d",&a[i]);
for(i=0;i<62;i++)if(T>>i&1)solve(i);
for(i=0;i<n;i++)printf("%d ",a[i]);
}

  

XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea的更多相关文章

  1. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of SPb

    A. Base $i - 1$ Notation 两个性质: $2=1100$ $122=0$ 利用这两条性质实现高精度加法即可. 时间复杂度$O(n)$. #include<stdio.h&g ...

  2. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia

    1. GUI 按题意判断即可. #include<stdio.h> #include<iostream> #include<string.h> #include&l ...

  3. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof

    A. City Wall 找规律. #include<stdio.h> #include<iostream> #include<string.h> #include ...

  4. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Khamovniki

    A. Ability Draft 记忆化搜索. #include<stdio.h> #include<iostream> #include<string.h> #i ...

  5. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Saratov

    A. Three Arrays 枚举每个$a_i$,双指针出$b$和$c$的范围,对于$b$中每个预先双指针出$c$的范围,那么对于每个$b$,在对应$c$的区间加$1$,在$a$处区间求和即可. 树 ...

  6. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Khamovniki Problem J Stairways解题报告(分块+维护凸壳)

    首先ORZ一发Claris聚聚的题解:http://www.cnblogs.com/clrs97/p/8689215.html,不然我可能没机会补过这道神题了. 这里写一个更详细的题解吧(我还是太菜了 ...

  7. XVII Open Cup named after E.V. Pankratiev. Grand Prix of America (NAIPC-2017)

    A. Pieces of Parentheses 将括号串排序,先处理会使左括号数增加的串,这里面先处理减少的值少的串:再处理会使左括号数减少的串,这里面先处理差值较大的串.确定顺序之后就可以DP了. ...

  8. XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem D. Great Again

    题目: Problem D. Great AgainInput file: standard inputOutput file: standard outputTime limit: 2 second ...

  9. XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem K. Piecemaking

    题目:Problem K. PiecemakingInput file: standard inputOutput file: standard outputTime limit: 1 secondM ...

随机推荐

  1. MySQL 导出数据库,出现 “mysqldump: Got error: 1146”

    出现场景 在 cmd 导出数据库时: mysqldump -hlocalhost -uroot -p student_db > C:\student_db.sql 出现: mysqldump: ...

  2. 深入理解pthread_cond_wait、pthread_cond_signal

    ===============================man pthread_cond_wait的解释========================== LINUX环境下多线程编程肯定会遇到 ...

  3. [SDOI2006] 保安站岗

    题目链接 第一遍不知道为什么就爆零了…… 第二遍改了一下策略,思路没变,结果不知道为什么就 A 了??? 树形 DP 经典问题:选择最少点以覆盖树上所有点(边). 对于本题,设 dp[i][0/1][ ...

  4. 应用调试(二)GDB

    title: 应用调试(二)GDBdate: 2019/1/17 21:00:10 toc: true 应用调试(二)GDB gdb下载工具安装交叉工具链设置GDB介绍编译GDBtarget/host ...

  5. Windows 环境下的 protoc 安装(转)

    如果是为了编译hadoop2.8.0源码,必须使用2.5.0版本的protobuf,安装方法同下 1. 下载需要的安装包:https://github.com/google/protobuf/rele ...

  6. LCA(ST倍增)

    时间复杂度: dfs树,求st表(状态数组f):O(NlgN) 处理M个查询:O(MlgN) 总:O((M+N)lgN) #include<iostream> #include<cs ...

  7. Regularity criteria for NSE 5: $u_3,\om_3$

    In [Zhang, Zujin. Serrin-type regularity criterion for the Navier-Stokes equations involving one vel ...

  8. Best Practice API

    # 建议直接使用的第三方类 Common Lang =>StringUtils =>Validate Guava =>Cache =>Ordering JDK7(LTS JDK ...

  9. java8 按对象属性值排序

    //按id从小到大 List<User> sortUser = list.stream().sorted((u1, u2) -> u1.getId().compareTo(u2.ge ...

  10. java(8)二重循环

    一.二重循环 1.循环中,嵌套另外一个循环,将内层的循环,看成外层循环的一个循环操作 2.常见的二重循环 形式1:      外层while或do…while 内层为for循环 形式2: 外层.内层都 ...