题目
T1
手动玩几组样例就可以发现:如果给出的马匹数的GCD不能整除a,则不满足第一个条件;如果马匹数最小的那个的平方根
≤
\le
≤a,则不满足第二个条件;
注意:如果在判断第二个条件时计算
a
2
a^2
a2而不是
c
i
\sqrt{c_i}
ci,会
l
o
n
g
l
o
n
g
long \ long
long long。
#include <bits/stdc++.h>
using namespace std;
const int N=700050;
int n,q,b[N];
long long minn=1e18;
long long c[N],a[N],GCD,h;
inline long long read(){
long long cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
return cnt*f;
}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
n=read();
for(int i=1;i<=n;i++){
c[i]=read();minn=min(c[i],minn);GCD=gcd(GCD,c[i]);
}
q=read();
int h=ceil(sqrt(minn));
for(int i=1;i<=q;i++){
a[i]=read(),b[i]=read();
if(b[i]==1){
if(GCD%a[i]==0){
printf("Yes\n");
}
else{
printf("No\n");
}
}
if(b[i]==2){
if(h<=a[i]){
printf("No\n");
}
else{
printf("Yes\n");
}
}
}
return 0;
}
T2
思路: 桶套桶
第一层桶:记录标本串中每个字母出现的次数
c
n
t
cnt
cnt标本串的第一层桶
c
n
t
2
cnt2
cnt2枚举区间的第一层桶
第二层桶:以第一层桶为下标,统计每个元素出现次数的次数
g
g
g标本串的第二层桶
f
f
f枚举区间的第二层桶
记录一个
t
o
t
tot
tot,方便我们计算当前是否合法
当枚举区间的子串和标本串的第二层桶各项的差的绝对值之和为
0
0
0时,这两者中第二层桶的值一一对应,即可以通过变换得到
感谢kma的blog
#include <bits/stdc++.h>
#define N 2010
#define D 26
using namespace std;
bool isabc(char ch){return (ch>='a')&&(ch<='z');}
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
return cnt*f;
}
int T,len,m,Q;
int L,R,tot;
int cnt[D],cnt2[D];
int q[N][D],g[N],f[N];
bool vis[N];
int tmp;
char ch;
int s[N],ans;
void add(int x,int sig){
if(f[cnt2[x]]>g[cnt2[x]])tot--;else tot++;
f[cnt2[x]]--;
cnt2[x]+=sig;
if(f[cnt2[x]]>=g[cnt2[x]])tot++;else tot--;
f[cnt2[x]]++;//
return;
}
int main(){
T=read();
while(T--){
m=read(),Q=read();
tmp=0;ch=getchar();
for(;!isabc(ch);ch=getchar());
for(;isabc(ch);ch=getchar()) s[++tmp]=ch-'a';
for(int i=1;i<=m;i++){
for(int j=0;j<D;j++){q[i][j]=q[i-1][j];}
q[i][s[i]]++;
}
while(Q--){
for(int i=0;i<D;i++){cnt[i]=cnt2[i]=0;}
L=read(),R=read();
len=R-L+1;
for(int i=0;i<D;i++){
cnt[i]=q[R][i]-q[L-1][i];
cnt2[i]=q[len][i];//??
g[cnt[i]]++;f[cnt2[i]]++;
}
tot=0;
for(int i=0;i<D;i++){
if(!vis[cnt[i]]){
vis[cnt[i]]=true;
tot+=g[cnt[i]];
}
}
for(int i=0;i<D;i++){
vis[cnt[i]]=false;
}
for(int i=0;i<D;i++){
if(!vis[cnt2[i]]){
vis[cnt2[i]]=true;
if(f[cnt2[i]]>g[cnt2[i]])tot+=f[cnt2[i]]-2*g[cnt2[i]];//??
else tot-=f[cnt2[i]];
}
}
for(int i=0;i<D;i++){vis[cnt2[i]]=false;}
ans=0;
if(!tot)ans++;
for(int i=len+1;i<=m;i++){
add(s[i],1);add(s[i-len],-1);
if(!tot) ans++;
}
printf("%d\n",ans);
for(int i=0;i<D;i++){
g[cnt[i]]--;f[cnt2[i]]--;
}
}
}
return 0;
}
T3
由题意
- 一个节点会给他到首都的最短路径上的所有城市再贡献 a u a_u au点魅力值
- 因为不想让自己一开始就受不了或者心理落差太大,作为起点的城市的不能是这条路径经过的所有城市的的最大值或者最小值.
故可以得到:当
d
e
p
[
u
]
>
d
e
p
[
v
]
&
&
u
,
v
dep[u]>dep[v]\&\&u,v
dep[u]>dep[v]&&u,v在一条链上时,
f
u
>
f
v
f_u> f_v
fu>fv
即:一个节点子树上的点的
f
f
f值必定小于它自己的
f
f
f值。
得到思路:对于一个点
i
i
i,
g
i
g_i
gi是所有
f
j
<
f
i
f_j<f_i
fj<fi且
j
j
j不在以
i
i
i的子树中的节点
j
j
j的
∑
f
j
\sum{f_j}
∑fj。
f
r
o
m
s
o
l
u
t
i
o
n
:
from\ solution:
from solution:
我们考虑如何来计算gi
由于按位或运算每一个二进制位是互不干扰的,所以我们可以对于每一个二进制位分别考虑答案是多少,再累加起来。
所以,我们现在来一位位考虑。
一个关于按位或的基础性质:如果这些数当中有一个在这一位上是1,那按位或起来的结果在这一位上就是1;否则是0。
首先,因为gi是所有fj值比fi小的,且不在以i为根的子树中的fj的和。我们立马就会想到可以按照fi排序,那样我们按照fi由小到大处理,统计到fi的时候就可以统计出所有比fi小的f,在当前处理的这一二进制位上1的个数cnt。
由于在i的子树中,所有节点的f值都小于fi,所以我们这个cnt要减去以i为根的子树中(不包括i自己)在当前二进制位下1的个数hi
如果cnt大于0,我们就可以知道gi在当前这一二进制位下是1。
至于hi,使用类似于fi的方法统计即可。
时间复杂度:
O
(
n
l
o
g
2
n
)
O(nlog2n)
O(nlog2n)
内网solution
代码(非二进制拆位):
先用
d
f
s
dfs
dfs预处理出
d
f
s
dfs
dfs序,
f
f
f值,获取最大的
f
f
f值(树状数组建立的区间)
c
a
l
c
calc
calc:预处理出它
d
f
s
dfs
dfs序的前缀和后缀
p
o
s
pos
pos:
d
f
s
dfs
dfs序对应的原点
c
c
c:前缀或的和(前缀处理
f
f
f或的和)
p
r
e
pre
pre:前缀,
d
f
s
dfs
dfs序在它前面的
s
u
f
suf
suf:后缀,
d
f
s
dfs
dfs序在它后面的
树状数组理解:
树状数组下标:建立在或的和上,把或的和二进制分成一段一段的区间
c
[
x
]
c[x]
c[x]:以
x
x
x为根的子树中所有叶节点的或之和
预处理出
d
f
s
dfs
dfs序的原因:对于一棵子树,其中
d
f
s
dfs
dfs序一定是一个连续的
(
l
,
r
)
(l,r)
(l,r)的区间,符合题意的所有点就是
d
f
s
dfs
dfs序在
[
1
,
l
−
1
]
∪
[
r
+
1
,
n
]
[1,l-1]∪[r+1,n]
[1,l−1]∪[r+1,n]的点。
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 1e6 + 5, M = 1e7 + 5;
int lowbit(int x){
return x&(-x);
}
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
int fir[N], nxt[N << 1], to[N << 1], tot;
void add(int x, int y){
nxt[++tot] = fir[x], fir[x] = tot, to[tot] = y;
}
int n, Cap, Mx;
int a[N], ans[N];
int in[N], out[N], pos[N], ind;
struct BIT{
int c[M];
void clear(){memset(c,0,sizeof(c));}
void add(int x,int v){for(;x<=Mx;x+=lowbit(x))c[x]|=v;}
int ask(int x){int ans=0;for(;x;x-=lowbit(x)) ans|=c[x]; return ans;}
}bit;
void dfs_(int u,int fa){
in[u]=++ind;pos[ind]=u;
for(int i=fir[u];i;i=nxt[i]){
int v=to[i];
if(v==fa) continue;
dfs_(v,u);a[u]+=a[v];
}
out[u]=ind;Mx=max(Mx,a[u]);
}
vector<int> pre[N],suf[N];
int calc(int x){
if(in[x]>1) pre[in[x]-1].push_back(x);
if(out[x]<n) suf[out[x]+1].push_back(x);
}
int main(){
int size=40<<20;//40M
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个
n=read(),Cap=read();
for(int i=1;i<n;i++){
int x,y;x=read(),y=read();add(x,y);add(y,x);
}
for(int i=1;i<=n;i++){
a[i]=read();
}
dfs_(Cap,0);
for(int i=1;i<=n;i++) calc(i);
for(int i=1;i<=n;i++){
bit.add(a[pos[i]],a[pos[i]]);
for(int j=0;j<pre[i].size();j++){
int nx=pre[i][j];
ans[nx]|=bit.ask(a[nx]-1);
}
}
bit.clear();
for(int i=n;i>=1;i--){
bit.add(a[pos[i]],a[pos[i]]);
for(int j=0;j<suf[i].size();j++){
int nx=suf[i][j];
ans[nx]|=bit.ask(a[nx]-1);
}
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
exit(0);
}
标程:
#include<bits/stdc++.h>
#define LL long long
#define MAXN 500000
using namespace std;
template<typename T>void Read(T &cn)
{
char c;int sig = 1;
while(!isdigit(c = getchar()))if(c == '-')sig = -1; cn = c-48;
while(isdigit(c = getchar()))cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
if(cn < 0) {putchar('-'); cn = 0-cn; }
int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
while(cn)cm = cm*10+cn%10,cn/=10,wei++;
while(wei--)putchar(cm%10+48),cm/=10;
putchar(cx+48);
}
struct qwe{
int a,b,ne;
};
struct qwer{
int a,b;
inline friend bool operator <(qwer a,qwer b) {return a.a < b.a; }
void mk(int cn,int cm) {a = cn; b = cm; }
};
qwe a[MAXN*2+1];
int alen;
int head[MAXN+1];
int n,ro;
int fa[MAXN+1],f[MAXN+1],zhi[MAXN+1];
qwer lie[MAXN+1];
int ans[MAXN+1];
int ge[MAXN+1][24];
void lian(int cn,int cm)
{
a[++alen].a = cn;
a[alen].b = cm;
a[alen].ne = head[cn];
head[cn] = alen;
}
void dfs(int cn)
{
f[cn] = zhi[cn];
for(int i = head[cn];i;i = a[i].ne)
{
int y = a[i].b;
if(y == fa[cn])continue;
fa[y] = cn;
dfs(y);
f[cn] = f[cn] + f[y];
}
}
void set_ge(int cn,int cm)
{
for(int i = 0;i<=cm;i++)ge[cn][i] = 0;
for(int i = head[cn];i;i = a[i].ne)
{
int y = a[i].b;
if(y == fa[cn])continue;
set_ge(y,cm);
for(int j = 0;j<=cm;j++)ge[cn][j] = ge[cn][j] + ge[y][j] + ((f[y]&(1<<j)) != 0);
}
}
int erwei(int cn) {int guo = 0; while(cn)guo++,cn >>= 1; return guo; }
void zuo(int cn)
{
int he = 0,lei = 0; lie[0].a = lie[1].a-1;
for(int i = 1;i<=n;i++)
{
if(lie[i-1].a != lie[i].a)he += lei,lei = 0;
ans[lie[i].b] |= (1<<cn)*(he > ge[lie[i].b][cn]);
lei += ((f[lie[i].b] & (1<<cn)) != 0);
}
}
int main()
{
freopen("forever.in","r",stdin);
freopen("forever.out","w",stdout);
Read(n); Read(ro);
alen = 0; memset(head,0,sizeof(head));
for(int i = 1;i<n;i++)
{
int bx,by; Read(bx); Read(by);
lian(bx,by); lian(by,bx);
}
for(int i = 1;i<=n;i++)Read(zhi[i]);
fa[ro] = 0;
dfs(ro);
for(int i = 1;i<=n;i++)lie[i].mk(f[i],i);
sort(lie+1,lie+n+1);
for(int i = 1;i<=n;i++)ans[i] = 0; int lin = erwei(f[ro]);
set_ge(ro,lin);
for(int i = 0;i<=lin;i++)zuo(i);
for(int i = 1;i<=n;i++)Write(ans[i]),putchar(' '); putchar('\n');
return 0;
}