A
解法一(官方解法):
要求每段的二進位制或都相同,那麼如果整個序列中存在某個數的第 \(i\) 位為 \(1\),那麼整個序列的每一段長
度為 \(k\) 的連續子序列中都至少有一個數的第 \(i\) 位為 \(1\)。
我們可以對每一位單獨求一個滿足條件的最小的 \(k\),然後所有位的 \(k\) 的最大值就是答
案。
對於每一位,其序列都形如 00010110001... 這樣的二進位制串,要求每連續 \(k\) 個位置都至少包含一個 \(1\)。
這是一個很經典的問題,可以用雙指標或滑動視窗等方法來實現。
解法二:
注意到或運算本質上和加法是差不多的,都有單調性,所以可以用線段樹+二分求解,其中把線段樹中所有的 + 變為 | 即可。
bool mst;
int n,m;
#define ls (p<<1)
#define rs (p<<1|1)
#define int long long
const int N = 5000005;
int a[N];
struct point
{
int sum,lazy;
}t[N*4];
struct segtree
{
void push_up(int p)
{
t[p].sum = t[ls].sum|t[rs].sum;
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p].sum = a[l];
return;
}
int mid = (l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(p);
}
int get(int p,int L,int R,int l,int r)
{
if(L<=l&&r<=R)
return t[p].sum;
int ans = 0;
int mid = (l+r)/2;
if(L<=mid)
ans |= get(ls,L,R,l,mid);
if(R>mid)
ans |= get(rs,L,R,mid+1,r);
return ans;
}
}bird;
bool check(int x)
{
int c1,c2;
int i;
for(i=1;i<=n-x+1;i++)
{
c2 = c1;
c1 = bird.get(1,i,i+x-1,1,n);
if(~-i&&c1!=c2)
return 0;
}
return 1;
}
bool men;
void solve()
{
cin>>n;
int i;
for(i=1;i<=n;i++)
cin>>a[i];
bird.build(1,1,n);
int l,r;
l = 1,r = n;
while(l<r)
{
int mid = (l+r)/2;
if(check(mid))
r = mid;
else
l = mid+1;
}
cout<<r<<endl;
return;
}
B
解法一(官方解法):
程式碼很簡單,不給了。
解法二:
可以將上述做法簡化,把 dfs 換成遞推的過程就可以了。
void solve()
{
cin>>n>>k;
int i;
for(i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
int s = k;
int j;
for(i=1;i<=n;i++)
for(j=2;j<=e[i].size();j++)
s *= k-j,s %= mod;
s *= k-1,s %= mod;
cout<<s%mod<<endl;
return;
}
C
void solve()
{
queue<int> q[50];
map<int,bool> ma;
cin>>n>>m;
cin>>s+1>>t+1;
int i,j;
for(i=1;i<=n;i++)
ma[s[i]-'a'+1] = 1,q[s[i]-'a'+1].push(i);
for(i=1;i<=m;i++)
{
if(q[t[i]-'a'+1].empty())
{
NO
return;
}
int j;
for(j=1;j<=t[i]-'a'+1;j++)
while(q[j].size()&&q[j].front()<q[t[i]-'a'+1].front())
q[j].pop();
q[t[i]-'a'+1].pop();
}
YES
return;
}