A. Ability Draft

记忆化搜索。

#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 = 1e5 + 10, 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, m, S, g;
int f[100][1<<10];
int p[100];
int s[100][10]; int sm, bg;
int smp, bgp;
int smk[100];
int bgk[100];
int cal(int o, int sta)
{
if(o > g)return 0;
if(~f[o][sta])return f[o][sta];
int x = p[o];
int y = p[o + 1];
f[o][sta] = -2e9; int canbig = ((sta >> x & 1) == 0);
int cansml = S - (s[o - 1][x] - (canbig == 0)); //canbig == 0 means we picked ulti int sgn = (x / n == y / n) ? 1 : -1;
if(canbig)
{
int add = bgk[++bgp];
f[o][sta] = max(sgn * cal(o + 1, sta | 1 << x) + add, f[o][sta]);
--bgp;
}
if(cansml)
{
int add = smk[++smp];
f[o][sta] = max(sgn * cal(o + 1, sta) + add, f[o][sta]);
--smp;
}
return f[o][sta];
}
int main()
{
while(~scanf("%d%d",&n, &S))
{
m = n * 2;
g = m * (S + 1);
for(int i = 1; i <= g; ++i)
{
scanf("%d", &p[i]); --p[i];
for(int j = 0; j < m; ++j)
{
s[i][j] = s[i - 1][j] + (j == p[i]);
}
}
scanf("%d", &sm);
for(int i = 1; i <= sm; ++i)scanf("%d", &smk[i]);
sort(smk + 1, smk + sm + 1);
reverse(smk + 1, smk + sm + 1);
scanf("%d", &bg);
for(int i = 1; i <= bg; ++i)scanf("%d", &bgk[i]);
sort(bgk + 1, bgk + bg + 1);
reverse(bgk + 1, bgk + bg + 1); smp = bgp = 0;
MS(f, -1);
printf("%d\n", cal(1, 0)*((p[1]/n==0)?1:-1));
}
return 0;
} /*
【trick&&吐槽】
1 1
1 2 2 1
2
5 3
2
7 2 1 2
2 1 1 2 2 1
4
4 8 8 9
2
6 7
(ans = 2) 2 1
1 3 4 2 2 4 3 1
6
1 4 4 8 9 11
5
14 11 10 8 5 【题意】 【分析】 【时间复杂度&&优化】 */

  

B. Short Random Problem

积分DP。

C. Block, Stock and Two Smoking Galaxy Notes

枚举领导者$S$,它需要满足度数至少为$\frac{n}{2}$。

枚举完领导后,将和$S$认识和不认识的分成两组二分图匹配即可。

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

#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=1010,M=10010;
int n,m,i,e[M][2],g[N],v[M],nxt[M],ed,f[N],b[N],T,right[N],deg[N];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
bool find(int x){
for(int i=g[x];i;i=nxt[i])if(b[v[i]]<T){
b[v[i]]=T;
if(!f[v[i]]||find(f[v[i]]))return f[v[i]]=x,1;
}
return 0;
}
void solve(int S){
int i;
for(i=1;i<=n;i++)right[i]=g[i]=0;
ed=0;
for(i=1;i<=m;i++){
if(e[i][0]==S)right[e[i][1]]=1;
if(e[i][1]==S)right[e[i][0]]=1;
}
for(i=1;i<=m;i++){
if(e[i][0]!=S&&!right[e[i][0]]&&right[e[i][1]])add(e[i][0],e[i][1]);
if(e[i][1]!=S&&!right[e[i][1]]&&right[e[i][0]])add(e[i][1],e[i][0]);
}
for(i=1;i<=n;i++)f[i]=b[i]=0;
T=0;
for(i=1;i<=n;i++){
if(right[i]||i==S)continue;
T++;
if(!find(i))return;
}
puts("Yes");
int cnt=0;
for(i=1;i<=n;i++)if(right[i])cnt++;
printf("%d %d\n",S,cnt);
for(i=1;i<=n;i++)if(right[i]){
printf("%d ",i);
if(!f[i])f[i]=-1;
printf("%d\n",f[i]);
}
exit(0);
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d%d",&e[i][0],&e[i][1]),deg[e[i][0]]++,deg[e[i][1]]++;
for(i=1;i<=n;i++)if(deg[i]>=n/2-5)solve(i);
puts("No");
}
/*
5 4
1 2
2 3
3 4
4 5
*/

  

D. Lunch Queue

用一棵平衡树$S$维护整个队列,再对每个队伍用一棵平衡树$T_i$维护。

那么对于新来的一个人,先在$S$中找出满足距离限制最紧的那个点$x$,再在$T_{c_i}$中查找$x$之后最靠前的点作为插队位置。

瓶颈在于最后一步比较两个人在$S$中的前后关系,将$S$用替罪羊树维护,同时维护动态标号即可$O(1)$比较。

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

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=400010;
typedef unsigned long long ll;
const ll inf=1ULL<<63;
const double A=0.8;
ll tl[N],tr[N],tm[N];
int size[N],son[N][2],f[N],tot,root;
int id[N],cnt;
int n,i,a[N];
void dfs(int x){
if(son[x][0])dfs(son[x][0]);
id[++cnt]=x;
if(son[x][1])dfs(son[x][1]);
}
int build(int fa,int l,int r,ll a,ll b){
int mid=(l+r)>>1,x=id[mid];
f[x]=fa;son[x][0]=son[x][1]=0;size[x]=1;tl[x]=a;tr[x]=b;tm[x]=(a+b)>>1;
if(l==r)return x;
if(l<mid)size[x]+=size[son[x][0]=build(x,l,mid-1,a,tm[x])];
if(r>mid)size[x]+=size[son[x][1]=build(x,mid+1,r,tm[x],b)];
return x;
}
inline int kth(int k){
if(k<1)return 0;
int x=root,rank;
while(1){
rank=size[son[x][0]]+1;
if(k==rank)return x;
if(k<rank)x=son[x][0];else k-=rank,x=son[x][1];
}
}
inline int rebuild(int x){
cnt=0;
dfs(x);
return build(f[x],1,cnt,tl[x],tr[x]);
}
inline void fix(int x){
int deep=1,z=x;
size[x]++;
while(f[z])size[z=f[z]]++,deep++;
if(deep<log(tot)/log(1/A))return;
while((double)size[son[x][0]]<A*size[x]&&(double)size[son[x][1]]<A*size[x])x=f[x];
if(!x)return;
if(x==root){root=rebuild(x);return;}
int y=f[x],b=son[y][1]==x,now=rebuild(x);
son[y][b]=now;
}
inline void ins(int A,int B,int x){
if(!root){
root=size[1]=1;
tr[1]=inf;
tm[1]=inf>>1;
return;
}
while(1){
if(!son[A][B]){
son[A][B]=x;
f[x]=A;
if(!B){
tl[x]=tl[A];
tr[x]=tm[A];
}else{
tl[x]=tm[A];
tr[x]=tr[A];
}
tm[x]=(tl[x]+tr[x])>>1;
break;
}
A=son[A][B];
}
fix(x);
}
inline void insd(int A,int B,int x){
if(!son[A][B]){
son[A][B]=x;
f[x]=A;
if(!B){
tl[x]=tl[A];
tr[x]=tm[A];
}else{
tl[x]=tm[A];
tr[x]=tr[A];
}
tm[x]=(tl[x]+tr[x])>>1;
fix(x);
return;
}
ins(son[A][B],B^1,x);
}
void show(int x){
if(son[x][0])show(son[x][0]);
printf("%d ",x);
if(son[x][1])show(son[x][1]);
}
namespace DS{
int root[N],son[N][2],f[N];
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;
}
inline void splay(int x){
while(f[x]){
int y=f[x];
if(f[y]){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
}
inline void insert(int&x,int y){
if(!x){x=y;return;}
int z=x;
while(1){
int b=tm[y]>tm[z];
if(son[z][b])z=son[z][b];
else{
son[z][b]=y;
f[y]=z;
break;
}
}
splay(x=y);
}
int ask(int&o,int y){
int t=0,z=0,x=o;
while(x){
z=x;
if(tm[x]>tm[y]){
t=x;
x=son[x][0];
}else{
x=son[x][1];
}
}
if(z)splay(o=z);
return t;
}
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++){
int x,dis;
scanf("%d%d",&x,&dis);
a[i]=x;
if(i==1)ins(0,0,i);
else{
int y=kth(i-dis-1);
if(a[y]==x)insd(y,1,i);
else{
int z=DS::ask(DS::root[x],y);
if(z)insd(z,0,i);
else ins(root,1,i);
}
}
DS::insert(DS::root[x],i);
}
show(root);
}

  

E. Oneness

$ans=\lfloor\frac{n}{11}\rfloor+\lfloor\frac{n}{111}\rfloor+\lfloor\frac{n}{1111}\rfloor+...$。

令$N=9n$,则$ans=\lfloor\frac{N}{99}\rfloor+\lfloor\frac{N}{999}\rfloor+\lfloor\frac{N}{9999}\rfloor+...$。

对于整数部分FFT计算答案,对于小数部分用实数近似计算即可。

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

F. Shuffle

对于置换中的每个循环,通过KMP求出所有可能的匹配位置,它们必然是一个等差数列。

那么对于所有循环分别列同余方程,然后扩展欧几里得求解即可。

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

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef int ll;
const int N=1000010;
int n,i,j,p[N],vis[N],q[N];
char a[N],b[N],c[N],S[N],T[N];
int nxt[N],w[N*4];
int ans=1;
int _a[N],_b[N],tot;
namespace NT{
int flag=1;
ll k=1,m,a,r,d,x,y;
ll exgcd(ll a,ll b,ll&x,ll&y){
if(!b)return x=1,y=0,a;
ll d=exgcd(b,a%b,x,y),t=x;
return x=y,y=t-a/b*y,d;
}
inline void add(ll a,ll r){
if(r>=a)while(1);
r%=a;
if(!flag)return;
d=exgcd(k,a,x,y);
if((r-m)%d){flag=0;return;}
x=(x*(r-m)/d+a/d)%(a/d),y=k/d*a,m=((x*k+m)%y)%y;
if(m<0)m+=y;
k=y;
}
void write(ll x){
if(x>=10)write(x/10);
int t=x%10;
printf("%d",t);
}
void show(){
if(flag)write(m);
else puts("-1");
}
}
inline void solve(int len){
int i,j,k,cnt=0;
for(i=1;i<=len;i++)T[i]=b[q[i]],S[i]=a[q[i]];
//printf("len=%d\n",len);
//for(i=1;i<=len;i++)putchar(T[i]);puts("");
//for(i=1;i<=len;i++)putchar(S[i]);puts("");
for(nxt[1]=j=0,i=2;i<=len;nxt[i++]=j){
while(j&&S[j+1]!=S[i])j=nxt[j];
if(S[j+1]==S[i])j++;
}
//for(i=1;i<=len;i++)printf("nxt[%d]=%d\n",i,nxt[i]);
for(i=1,j=0,k=1;i<=len*4;i++){
while(j&&S[j+1]!=T[k])j=nxt[j];
if(S[j+1]==T[k]){
j++;
if(j==len){
w[++cnt]=i-len;
j=nxt[j];
//printf("find %d\n",i);
}
}
k++;
if(k>len)k=1;
}
if(!cnt){
puts("-1");
exit(0);
}
if(cnt<2)while(1);
for(i=2;i<=cnt;i++)if(w[i]-w[i-1]!=w[2]-w[1])while(1);
//printf("per=%d occ=%d\n",w[2]-w[1],w[1]);
NT::add(w[2]-w[1],w[1]);
}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
scanf("%s%s",a+1,b+1);
n=strlen(a+1);
for(i=1;i<=n;i++){
int x;
if(i<=n/2)x=i*2-1;
else x=i*2-n;
//printf("! %d %d\n",i,x);
p[x]=i;
}
for(i=1;i<=n;i++)if(!vis[i]){
int cnt=0;
for(j=i;!vis[j];j=p[j])vis[j]=1,q[++cnt]=j;
//for(j=1;j<=cnt;j++)printf("%d ",q[j]);puts("");
solve(cnt);
}
NT::show();
}
/*
aaababbbbbbabbbbab
aabbabbababbbabbbb babaaabbaa
bbaaaababa
*/

  

G. Piecewise Linearity

按题意反解出每个函数即可,精度可以取模控制,不过使用__float128也可以通过全部数据。

#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 = 1e5 + 10, 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 xx[N], yy[N];
__float128 x[N], y[N], v[N], k[N];
const double EPS = 1e-9;
__float128 fabs(__float128 x)
{
return x >= 0 ? x : -x;
}
bool same(__float128 x, __float128 y)
{
x -= y;
return x <= EPS && x >= -EPS;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1; i <= n + 1; ++i)
{
scanf("%lf%lf", &xx[i], &yy[i]);
x[i] = xx[i];
y[i] = yy[i];
}
__float128 sum = 0;
__float128 yy = 0;
for(int i = 1; i <= n; ++i)
{
k[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
if(i >= 2)
{
v[i] = (k[i] - k[i - 1]) / 2;
sum += v[i];
yy += v[i] * fabs(x[1] - x[i]);
}
}
if(!same(sum, k[n]) || !same(-sum, k[1]) || !same(yy, y[1]))
{
puts("No");
}
else
{
puts("Yes");
}
}
return 0;
} /*
【trick&&吐槽】
2
-1 2
1 0
2 1 3
-3 -1
-1 -1
1 1
4 1 3
-3 1
-2 0
0 1
1 1 【题意】 【分析】 【时间复杂度&&优化】 */

  

H. Sketch

贪心将原序列复制下来,然后构造递减数列,注意特判原序列非法的情况。

#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 = 3e5 + 10, 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, m, k;
int a[N], b[N]; int main()
{
while(~scanf("%d%d%d", &k, &n, &m)){
a[0] = 1;
for(int i = 1; i <= k; i ++) {
scanf("%d", &a[i]);
if(a[i] == -1){
a[i] = a[i - 1];
}
}
int flag = 1;
for(int i = 2; i <= k; i ++){
if(a[i] < a[i - 1]) flag = 0;
}
if(k > n || !flag){
puts("-1");
continue;
}
int rst = n - k, o = 0;
for(int i = 1; i <= k; i ++){
int x = m;
while(rst > 0){
if(x == a[i]) break;
b[++ o] = x --;
rst --;
}
b[++ o] = a[i];
}
/*
if(rst){
int x = b[o] - 1;
while(rst > 0){
if(x == 0) break;
b[++ o] = x --;
rst --;
}
}
*/
if(rst){
puts("-1");
}
else{
for(int i = 1; i <= n; i ++) printf("%d ", b[i]);
puts("");
}
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */

  

I. $\leq$ or $\geq$

最优策略:将元素个数为$k$的栈的栈顶元素的权重设置为$2^{k-1}$,然后取加权中位数。

#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 = 1e5 + 10, 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, k, x;
int a[N], b[N];
char s[10];
int rst[N];
int w[20];
typedef pair<int,int>P;
P q[N];
LL pre[N][2],suf[N][2];
int main()
{
w[1]=1;
w[2]=2;
w[3]=4;
w[4]=8;
w[5]=16;
w[6]=32;
w[7]=64;
w[8]=128;
w[9]=256;
w[10]=512;
while(~scanf("%d%d",&n, &k))
{
for(int i = 1; i <= n; i ++) rst[i] = k;
while(1){
int num = 0;
int mx=0;
for(int i=1;i<=n;i++)mx=max(mx,rst[i]);
for(int i = 1; i <= n; i ++){
scanf("%d", &b[i]);
if(b[i])q[++num]=P(b[i],w[rst[i]]);
}
sort(q + 1, q + num + 1);
LL best=~0ULL>>1;
int pos=1;
for(int i=1;i<=num;i++){
pre[i][0]=pre[i-1][0]+1LL*q[i].first*q[i].second;
pre[i][1]=pre[i-1][1]+q[i].second;
}
suf[num+1][0]=suf[num+1][1]=0;
for(int i=num;i;i--){
suf[i][0]=suf[i+1][0]+1LL*q[i].first*q[i].second;
suf[i][1]=suf[i+1][1]+q[i].second;
}
for(int i=1;i<=num;i++){
LL now=1LL*q[i].first*pre[i][1]-pre[i][0];
now+=suf[i][0]-1LL*q[i].first*suf[i][1];
if(now<best)best=now,pos=i;
}
int y=q[pos].first;
printf("%d\n", y);
fflush(stdout);
scanf("%s", s);
if(s[0] == 'E'){
return 0;
}
else{
for(int i = 1; i <= n; i ++){
if(s[0] == '<' && b[i] <= y){
rst[i] --;
}
else if(s[0] == '>' && b[i] >= y){
rst[i] --;
}
}
}
}
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */

  

J. Stairways

设$pre[i]=\max(a[1..i])$,则对于任意一个前缀$i$来说,两个子序列必有一个的最大值为$pre[i]$,设$f[i][j]$表示考虑前缀$i$,除了$pre[i]$之外另一个子序列最大值为$j$时的最小代价,考虑如何从$f[i-1][]$转移到$f[i][]$。

若$a[i]=pre[i]$,那么显然将它归到较大一侧最优,故$f[i][j]=f[i-1][j]+a[i]$,只需要把答案加上$a[i]$即可。

否则$a[i]<pre[i]$,那么假设它不作为最大值,则对于$[a[i],pre[i]]$的$j$,有$f[i][j]=f[i-1][j]+j$,对于$[0,a[i])$的$j$,有$f[i][j]=f[i-1][j]+pre[i]$。

而如果它作为最大值,则有$f[i][a[i]]=\min(f[i-1][0..a[i]])+a[i]$。

故需要一个数据结构维护$f[j]$,支持区间加上一个数,区间每个位置$j$加上$j$,以及区间查询最小值,单点修改。

将$f$分块,每块维护凸壳和标记即可,因为查询横坐标递增,故不断将凸壳的队首弹出即可均摊$O(\sqrt{n})$每次查询。

时间复杂度$O(n\sqrt{n})$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,K=330;
const ll inf=1000000000000010LL;
int n,m,lim,i,a[N],b[N],pre[N],pos[N],st[K],en[K],tx[K],q[N],head[K],tail[K];
ll base,f[N],tb[K];
inline void up(ll&a,ll b){a>b?(a=b):0;}
inline double slope(int x,int y){return 1.0*(f[x]-f[y])/(b[y]-b[x]);}
inline void build(int x){
int&h=head[x],&t=tail[x],l=st[x],r=en[x];
h=l,t=h-1;
for(int i=r;i>=l;q[++t]=i--)while(h<t&&slope(q[t-1],q[t])>slope(q[t],i))t--;
}
inline void addx(int l){
int L=pos[l];
for(int i=l;i<=en[L];i++)f[i]+=b[i];
for(int i=pos[m];i>L;i--)tx[i]++;
}
inline void addf(int r,int p){
int R=pos[r];
for(int i=st[R];i<=r;i++)f[i]+=p;
build(R);
for(int i=0;i<R;i++)tb[i]+=p;
}
inline ll cal(int x,int y){return f[x]+1LL*y*b[x];}
inline ll ask(int x){
int&h=head[x],t=tail[x],o=tx[x];
while(h<t&&cal(q[h],o)>cal(q[h+1],o))h++;
return cal(q[h],o);
}
inline ll query(int r){
ll ret=inf;
int R=pos[r];
for(int i=st[R];i<=r;i++)up(ret,f[i]+1LL*tx[R]*b[i]+tb[R]);
for(int i=0;i<R;i++)up(ret,ask(i)+tb[i]);
return ret;
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]),base-=a[i],b[i]=a[i];
sort(b+1,b+n+1);
for(i=1;i<=n;i++)if(b[i]!=b[i-1])b[++m]=b[i];
for(lim=1;lim*lim<=m;lim++);
for(i=1;i<=n;i++)pre[i]=max(pre[i-1],a[i]);
for(i=0;i<=m;i++)pos[i]=i/lim;
for(i=0;i<=m;i++)en[pos[i]]=i;
for(i=m;~i;i--)st[pos[i]]=i;
for(i=0;i<=pos[m];i++)build(i);
for(i=1;i<=n;i++){
if(pre[i]==a[i]){
base+=a[i];
continue;
}
int x=lower_bound(b,b+m+1,a[i])-b;
ll t=query(x)+a[i];
addx(x);
addf(x-1,pre[i]);
up(f[x],t-tb[pos[x]]-1LL*tx[pos[x]]*b[x]);
build(pos[x]);
}
printf("%lld",query(m)+base);
}

  

K. Hiding a Tree

将所有可以修改编号的点的编号随机设置,然后再挑选一个影响答案的点修正异或值。

若当前方案不合法,则在有解的情况下是小概率事件,多轮随机即可。

注意生成随机编号的时候要避免与之前编号相同,因为根据生日悖论,在$10^9$内取$10^5$个随机数中有重复元素的概率超过$50\%$,会导致这一轮随机作废。

#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<set>
using namespace std;
const int N=100010;
int n,i,a[N],e[N][2],b[N],c[N],q[N],m,v[N];
int used[N];
set<int>T;
inline int ask(){
while(1){
int x=rand()%1000000000+1;
if(x<N&&used[x])continue;
if(T.find(x)!=T.end())continue;
T.insert(x);
return x;
}
}
void solve(){
T.clear();
for(i=1;i<=n;i++){
if(a[i])b[i]=ask();
else b[i]=i;
}
int ret=n;
for(i=1;i<=n;i++)if(v[i])ret^=b[i];
if(ret){
if(!m)return;
int x=rand()%m+1;
b[q[x]]^=ret;
}
for(i=1;i<=n;i++){
if(b[i]<1||b[i]>1000000000)return;
c[i]=b[i];
}
sort(c+1,c+n+1);
for(i=1;i<n;i++)if(c[i]==c[i+1])return;
printf("%d\n",n);
for(i=1;i<n;i++)printf("%d %d\n",b[e[i][0]],b[e[i][1]]);
exit(0);
}
int main(){
srand(time(NULL));
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
if(!a[i])used[i]=1;
}
for(i=1;i<n;i++){
scanf("%d%d",&e[i][0],&e[i][1]);
v[e[i][0]]^=1;
v[e[i][1]]^=1;
}
for(i=1;i<=n;i++)if(a[i]&&v[i])q[++m]=i;
for(int _=100;_;_--)solve();
puts("-1");
}

  

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

  1. 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,不然我可能没机会补过这道神题了. 这里写一个更详细的题解吧(我还是太菜了 ...

  2. 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 ...

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

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

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

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

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

    A. Donut 扫描线+线段树. #include<cstdio> #include<algorithm> using namespace std; typedef long ...

  6. 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$处区间求和即可. 树 ...

  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. linux线程(一)

    线程的优先级无法保障线程的执行次序.只不过优先级高的线程获取 CPU 资源的概率大一点而已. 线程相关函数(1)-pthread_create(), pthread_join(), pthread_e ...

  2. KNN算法的实现

    K近邻(KNN)算法简介 KNN是通过测量不同特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其 ...

  3. [物理学与PDEs]第1章习题12 Coulomb 规范下电磁场的标势、矢势满足的方程

    试给出在 Coulomb 规范下, 电磁场的标势 $\phi$ 与矢势 ${\bf A}$ 所满足的方程. 解答: 真空中的 Maxwell 方程组为 $$\bee\label{1_10_12:eq} ...

  4. MyEclipse编码方式设置

    1.windows -> Preferences -> general -> Workspace:

  5. 在JS中如何判断所输入的是一个数、整数、正数、非数值?

    1.判断是否为一个数字: Number(num)不为 NaN,说明为数字 2. 判断一个数为正数: var num=prompt("请输入:"); if(Number(num)&g ...

  6. UE4 AR开发笔记

    1.基础使用 ArToolKit:生成图片特征,可以用彩图.(图片先灰化)    genTexData效准相机.由于有的相机照相有弧度.  calib_camera 2.使用UE4ARPlugins做 ...

  7. ps常用指令集

    M DCtrl+ D清空选择区域Ctrl+ R调出标尺

  8. Alpha 事后诸葛亮(团队)

    前言 事后诸葛亮?作业名真的不好听,下一届还要沿用吗? 队名:小白吃 通向hjj博客的任意门 思考总结 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? ...

  9. 【原创】大叔经验分享(6)Oozie如何查看提交到Yarn上的任务日志

    通过oozie job id可以查看流程详细信息,命令如下: oozie job -info 0012077-180830142722522-oozie-hado-W 流程详细信息如下: Job ID ...

  10. 【原创】大叔问题定位分享(27)spark中rdd.cache

    spark 2.1.1 spark应用中有一些task非常慢,持续10个小时,有一个task日志如下: 2019-01-24 21:38:56,024 [dispatcher-event-loop-2 ...