Petrozavodsk Summer-2017. Moscow IPT Contest
A. A Place For My Head
留坑。
B. New Divide
从高位到低位贪心,当这一位是$0$时,要尽量取$1$,维护高维后缀最小值进行判断即可。
时间复杂度$O((n+a)\log a)$。
#include<cstdio> const int N=1000010,M=1048576; int n,i,j,a[N],v[M]; inline void up(int&a,int b){a>b?(a=b):0;} inline int query(int p,int w){ int x=0; for(int i=19;~i;i--)if(!(p>>i&1))if(v[x|(1<<i)]<=w)x|=1<<i; return (p^x)+x; } int main(){ scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&a[i]),a[i]^=a[i-1]; for(i=0;i<M;i++)v[i]=N; for(i=n;~i;i--)v[a[i]]=i; for(i=M-1;~i;i--)for(j=0;j<20;j++)if(!(i>>j&1))up(v[i],v[i^(1<<j)]); for(i=1;i<=n;i++)printf("%d ",query(a[i],i)); }
C. Lying From You
留坑。
D. Don’t Stay
留坑。
E. In The End
留坑。
F. From The Inside
留坑。
G. Numb
留坑。
H. One Step Closer
留坑。
I. Invisible
给每个数一个随机的权值,那么若所有数权值的异或和不为$0$,则说明存在出现奇数次的数字。
权值线段树套线段树维护异或和,在权值线段树上往下走即可。
时间复杂度$O(n\log^2n)$。
#include<cstdio> typedef unsigned int ll; const int N=100010,M=40000000; ll f[N]; int n,m,i,op,x,y,a[N]; int tot,l[M],r[M];ll v[M]; int T[300000]; void INS(int&x,int a,int b,int c,ll p){ if(!x){ x=++tot; } v[x]^=p; if(a==b)return; int mid=(a+b)>>1; if(c<=mid)INS(l[x],a,mid,c,p); else INS(r[x],mid+1,b,c,p); } void ins(int x,int a,int b,int c,int d,ll p){ INS(T[x],1,n,d,p); if(a==b)return; int mid=(a+b)>>1; if(c<=mid)ins(x<<1,a,mid,c,d,p); else ins(x<<1|1,mid+1,b,c,d,p); } ll ask(int x,int a,int b,int c,int d){ if(!x)return 0; if(c<=a&&b<=d)return v[x]; int mid=(a+b)>>1;ll t=0; if(c<=mid)t=ask(l[x],a,mid,c,d); if(d>mid)t^=ask(r[x],mid+1,b,c,d); return t; } inline int query(int c,int d){ int x=1,a=1,b=N; while(a<b){ int mid=(a+b)>>1; if(ask(T[x<<1],1,n,c,d)){ b=mid; x<<=1; }else{ a=mid+1; x=x<<1|1; } } if(!ask(T[x],1,n,c,d))return -1; return a; } int main(){ for(i=1;i<N;i++)f[i]=f[i-1]*233+17; scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&a[i]),ins(1,1,N,a[i],i,f[a[i]]); while(~scanf("%d",&m)){ if(!m)return 0; while(m--){ scanf("%d%d%d",&op,&x,&y); if(op==1){ ins(1,1,N,a[x],x,f[a[x]]); a[x]=y; ins(1,1,N,a[x],x,f[a[x]]); }else{ printf("%d\n",query(x,y)); fflush(stdout); } } } }
J. Leave Out All The Rest
两边的LIS都可以取到。
#include<cstdio> const int N=1000010; int n,m,i,j,x,a[N],b[N],cnt,c[N],ans; inline void add(int x){ if(x>c[cnt]){c[++cnt]=x;return;} int l=1,r=cnt,mid,t; while(l<=r)if(c[mid=(l+r)>>1]>=x)r=(t=mid)-1;else l=mid+1; c[t]=x; } int main(){ scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&x),add(x); ans=cnt; cnt=0; scanf("%d",&m); for(i=1;i<=m;i++)scanf("%d",&x),add(x); printf("%d",cnt+ans); }
K. Faint
找规律发现每个数的贡献和组合数有关。
#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() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #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 = 1e5 + 10, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } const int LIM=3000000; int casenum, casei; LL n, K, m; LL fac[LIM],inv[LIM]; int c(int n, int m) { if(n<m)return 0; return fac[n]*inv[m]%Z*inv[n-m]%Z; //LL rtn = 1; //for(int i = m + 1; i <= n; ++i)rtn *= i; //for(int i = 1; i <= n - m; ++i)rtn /= i; //return rtn; } int main() { int i; for(fac[0]=i=1;i<LIM;i++)fac[i]=1LL*fac[i-1]*i%Z; for(inv[0]=inv[1]=1,i=2;i<LIM;i++)inv[i]=1LL*(Z-inv[Z%i])*(Z/i)%Z; for(i=2;i<LIM;i++)inv[i]=1LL*inv[i-1]*inv[i]%Z; while(~scanf("%lld%lld%lld", &n, &K, &m)) { if(m == 1) { printf("%d\n", n - K); continue; } int sum = 0; int val = 0; for(int i = 1; i <= n - K; ++i) { int num = c(i - 1 + m - 2, i - 1); sum += num; sum%=Z; val += 1LL*num * i%Z; val%=Z; } int top = 1LL*sum * (n - K + 1)%Z; int bot = val; //printf("%d\n", top); printf("%d\n", bot); LL ans = 1LL*(top - bot) * 2 - (n - K); printf("%lld\n", (ans%Z+Z)%Z); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */