XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea
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的更多相关文章
- 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 ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia
1. GUI 按题意判断即可. #include<stdio.h> #include<iostream> #include<string.h> #include&l ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof
A. City Wall 找规律. #include<stdio.h> #include<iostream> #include<string.h> #include ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Khamovniki
A. Ability Draft 记忆化搜索. #include<stdio.h> #include<iostream> #include<string.h> #i ...
- 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$处区间求和即可. 树 ...
- 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,不然我可能没机会补过这道神题了. 这里写一个更详细的题解吧(我还是太菜了 ...
- XVII Open Cup named after E.V. Pankratiev. Grand Prix of America (NAIPC-2017)
A. Pieces of Parentheses 将括号串排序,先处理会使左括号数增加的串,这里面先处理减少的值少的串:再处理会使左括号数减少的串,这里面先处理差值较大的串.确定顺序之后就可以DP了. ...
- 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 ...
- 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 ...
随机推荐
- 机器学习 - 正则化L1 L2
L1 L2 Regularization 表示方式: $L_2\text{ regularization term} = ||\boldsymbol w||_2^2 = {w_1^2 + w_2^2 ...
- Dubbo学习笔记8:Dubbo的线程模型与线程池策略
Dubbo默认的底层网络通讯使用的是Netty,服务提供方NettyServer使用两级线程池,其中 EventLoopGroup(boss) 主要用来接受客户端的链接请求,并把接受的请求分发给 Ev ...
- 第六节:WebApi的部署方式(自托管)
一. 简单说明 开篇就介绍过WebApi和MVC相比,其中优势之一就是WebApi可以不依赖于IIS部署,可以自托管,当然这里指的是 .Net FrameWork 下的 WebApi 和 MVC 相比 ...
- VSCode CSS自动补充前缀
1.安装AuotPrefixer. 2.代码里写css样式后,Ctrl+Shift+P,选择AutoPrefix CSS执行 结果如下
- SSH框架之hibernate《四》
hibernate第四天 一.JPA相关概念 1.1JPA概述 全称是:Java Persistence API.是sun公司推出的一套基于ORM的规范 ...
- 分享一个jsonp劫持造成的新浪某社区CSRF蠕虫
最近jsonp很火,实话说已经是被玩烂了的,只是一直没有受到大家的重视.正好在上个月,我挖过一个由于jsonp造成的新浪某社区CSRF,当时是为了准备一篇文章,之后这篇文章也会拿出来分享. 因为新浪已 ...
- 在桌面右键创建html,css,js文件
1.在开始里面输入regedit,进入注册表编辑器. 2.打开HKEY_CLASSES_ROOT项. 3.打开.html/.css/.js项. 4.右键新建项,起名ShellNew. 5.新建字符串值 ...
- nnet3配置中的“编译”
编译概述 编译流程将Nnet和ComputationRequest作为输入,输出NnetComputation.ComputationRequest包含可用的输入索引 以及 请求的输出索引. 不提供输 ...
- Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC
解决Invalid character found in the request target. The valid characters are defined in RFC 7230 and RF ...
- Spring Cloud 2-Hystrix 断路容错保护(四)
Spring Cloud Hystrix 1.RestTemplate 容错 pom.xml application.yml application.java HelloService.java ...