### 2016弱校聯萌十一專場10.5

A.

```//倍增
#include <cstdio>
#include <cstring>

char s[100005];
int m, n, pe, pa, ps, py, dep;
int pre[100005], ed[100005];
int fa[100005][20];

int main() {
scanf("%s", s);
scanf("%d", &m);
n = strlen(s);
for (int i = 0; i < n; ++i) {
if (s[i] == 'e') {
pre[i + 1] = py;
pe = i + 1;
}
if (s[i] == 'a') {
pre[i + 1] = pe;
pa = i + 1;
}
if (s[i] == 's') {
pre[i + 1] = pa;
ps = i + 1;
}
if (s[i] == 'y') {
pre[i + 1] = ps;
py = i + 1;
}
ed[i + 1] = py;
}
for (int i = 1; i <= n; ++i) fa[i][0] = pre[i];
for (dep = 1; 1 << dep < n; ++dep);
for (int i = 1; i < dep; ++i)
for (int j = 1; j <= n; ++j)
fa[j][i] = fa[fa[j][i - 1]][i - 1];
for (; m--;) {
int l, r;
scanf("%d%d", &l, &r);
int x = ed[r];
int res = 1;
for (int i = dep - 1; i >= 0; --i) {
if (fa[x][i] >= l) {
x = fa[x][i];
res += 1 << i;
}
}
printf("%d\n", res / 4);
}
return 0;
}```
View Code

B.

trie樹碰到有左右子樹的，對1個子樹暴力查詢另1子樹的元素，得到最小異或和權值o(nlogm)

```#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, tot;
ll ans;
int a[4000009][2];
int num[4000009];
int dp[400009], dd[400009];
int dp1[400009], dd1[400009];
{
int q = 0;
++num[0];
for(int i = 30; ~i; --i)
{
bool w = x >> i & 1;

if(!a[q][w])
{
a[q][w] = ++tot;
}
++num[q = a[q][w]];
}
}
void zz(int x, int t)
{
if(t == -1)return ;
int l = a[x][0], r = a[x][1];
if(l && num[l] > 1)zz(l, t - 1);
if(r && num[r] > 1)zz(r, t - 1);
if(!l || !r)return ;
if(num[l] && num[r])
{
int q = 1 << t, *q1 = dp, *w1 = dd, *q2 = dp1, *w2 = dd1, num1 = 1, num2;
q1[0] = l;
w1[0] = r;
for(int i = t - 1; ~i; --i)
{
bool f = 1;
for(int j = 0; j < num1; ++j)
{
if((a[q1[j]][0]&&a[w1[j]][0]&&num[a[q1[j]][0]] && num[a[w1[j]][0]])
|| (a[q1[j]][1]&&a[w1[j]][1]&&num[a[q1[j]][1]] && num[a[w1[j]][1]]))
{
f = 0;
break;
}
}
num2 = 0;
for(int j = 0; j < num1; ++j)
{
if(a[q1[j]][0]&&a[w1[j]][f]&&num[a[q1[j]][0]] && num[a[w1[j]][f]])
{
q2[num2] = a[q1[j]][0];
w2[num2++] = a[w1[j]][f];
}
if(a[q1[j]][1]&&a[w1[j]][1 ^ f]&&num[a[q1[j]][1]] && num[a[w1[j]][1 ^ f]])
{
q2[num2] = a[q1[j]][1];
w2[num2++] = a[w1[j]][1 ^ f];
}
}
swap(q1, q2);
swap(w1, w2);
swap(num1, num2);
if(f)q |= 1 << i;
}
ans += q;
}
}
int main()
{
ans=0;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
int p;
scanf("%d", &p);
}
zz(0, 30);
printf("%lld\n", ans);
}```
View Code

C.

D.

E.

gcd(dx,dy)!=1 騎士只能走指定的格集合

(dx+dy)%2==0 那些(x+y)%2==1的點走不到

dy>m/2 騎士不能走2個方向，使得一些點走不到

dx+dy>n 中間區域無法到達

f(m,n) o(1)求出，答案因為floor()可以歸並某些答案的關系，可以o(sqrt(min(m,n)))

F.

fib數列其實有循環節的，當運行到f(k-1)%k==k-1 f(k)==1 那循環節就是k

lcm(...)是里面所有數的最小公倍數

H.

I.

```#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#include<assert.h>
using namespace std;
typedef long long ll;
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}

ll fac[21];
ll tal[20][10][2],pre[20][10][2];
//0:down,1:all
ll f(int n){return n<0?0:fac[n];}
void gettal()
{
fac[0]=1;
memset(tal,0,sizeof(tal));
memset(pre,0,sizeof(pre));
int i,j;
for(i=1;i<21;i++)fac[i]=fac[i-1]*i;
for(i=0;i<10;i++)tal[0][i][1]=1,tal[0][i][0]=0,pre[0][i][1]=pre[0][i][0]=i+1;
for(i=1;i<20;i++)
{
for(j=0;j<10;j++)
{
tal[i][j][0]=j==0?0:f(i+j-1)/f(j-1)/f(i);
tal[i][j][0]+=tal[i-1][j][0];

tal[i][j][1]=tal[i][j][0]+tal[i-1][j][1]-tal[i-1][j][0];
tal[i][j][1]+=j==9?0:f(8-j+i)/f(8-j)/f(i);

pre[i][j][0]=j?pre[i][j-1][0]+tal[i][j][0]:tal[i][j][0];
pre[i][j][1]=j?pre[i][j-1][1]+tal[i][j][1]:tal[i][j][1];
}
}
}
ll solve(ll n)
{
if(!n)return 1;
int i,j,path,ph;
ll tmp,ans=0;
for(i=0,tmp=1;n>=tmp;i++,tmp*=10);i--;tmp/=10;
int stat=1;
path=n/tmp;
ans+=pre[i][path-1][1]-pre[i][0][1];
tmp/=10;
for(i--;i>0;i--)
{
ans+=pre[i][9][1]-pre[i][0][1];
ph=(n%(tmp*10))/tmp;
if(stat==1)//keep
{
if(path>ph){stat=0;if(ph)ans+=pre[i][ph-1][0]+ph;}
else if(path==ph){if(ph)ans+=pre[i][ph-1][0]+ph;}
else
{
stat=2;
ans+=pre[i][ph-1][0]+ph;
ans+=tal[i][ph][1],
ans+=pre[i][ph-1][1]-pre[i][path][1];
ans-=pre[i][ph-1][0]-pre[i][path][0];
}
path=ph;
}
else if(stat==2)//increase
{
if(path>ph)
{
stat=3;
break;
}
ans+=pre[i][ph-1][1]-pre[i][path-1][1]-pre[i][ph-1][0]+pre[i][path-1][0];
path=ph;
}
else if(stat==0 && path)//decrease
{
if(ph)ans+=pre[i][min(path,ph)-1][0]+min(path,ph);
path=min(path,ph);
}
tmp/=10;
}
ans+=pre[0][9][1];
ph=(n%(tmp*10))/tmp;
if(stat==0)ans+=min(path,ph)+1;
else if(stat==1)ans+=ph+1;
else if(stat==2)ans+=max(0,ph-path+1);
return ans;
}
int main()
{
int t;
ll l,r;
gettal();
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}```
View Code

J.

```#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#include<assert.h>
using namespace std;
typedef long long ll;
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int a[2][200060];
int occupy[200060];
int main()
{
int n,j,i,t;
memset(occupy,-1,sizeof(occupy));
scanf("%d",&n);
for(j=0;j<2;j++)
{
for(i=0;i<n;i++)
{
scanf("%d",&t);
a[j][t]=i;
}
}
int cnt=n;
for(i=n*2-2;cnt;i--)
{
for(j=max(0,i-n+1);j<n && cnt;j++)
{
if(i<j)continue;
if(i-j>=n)break;
t=a[0][j]+a[1][i-j];
if(occupy[t%n]==-1)occupy[t%n]=i,cnt--;
}
}
for(i=0;i<n;i++)printf("%d%c",occupy[i],i==n-1?'\n':' ');
return 0;
}```
View Code