R1
D1
普及组。。。
T1/T2 咕
T3
链接:C
小A有一个只包含左右括号的字符串S。但他觉得这个字符串不够美观,因为它不是一个合法的括号串。一个合法的括号串是这样定义的:
()是合法的括号串
若A是合法的括号串,则(A)则是合法的括号串
若A,B是合法的括号串,则AB也是合法的括号串。
小A现在希望删掉S中若干个字符,使得剩下的字符串是一个合法的括号串。小A想知道有多少不同的方案。两个方案是不同的,当且仅当他们删除的位置不同。比如当S是(()时,有两种方案。分别是删掉第一个位置,或是删掉第二个位置。
dp,\(f[i][j]\)表示前\(i\)个位置未配平的左括号的个数为\(j\)的方案数,转移
\[f[i][j]=\left\{\begin{matrix} &s[i]='('\ \ | f[i][j]=f[i-1][j-1]+f[i-1][j]& \\ &s[i]='\ )'\ \ | f[i][j]=f[i-1][j]+f[i-1][j+1] & \end{matrix}\right.\]
标程是滚动数组,然鹅并不需要啊并不需要,直接压成一维数组即可,每次转移时左移或右移一位。
#include<iostream>
#include<cstdio>
using namespace std;
int i,m,n,j,k,a[1001][1001],b[10001],f[10001];
char c;
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
cin>>c;
if(c==')') b[i]=1;
}
f[0]=1;
for(i=1;i<=n;i++)
if(b[i]) for(j=1;j<=k;j++) f[j-1]+=f[j];
else {
k+=1;
for(j=k;j>=0;j--) f[j+1]+=f[j];
}
printf("%d",f[0]-1);
}
T4
链接:D
小A有n个长度都是L的字符串。这些字符串只包含前8个小写字符,'a'~'h'。但这些字符串非常的混乱,它们几乎长得互不相同。小A想通过一些规则,让它们长得尽可能相同。小A现在有K次机会,他可以每次机会,可以选择一对字符x,y,让x,y变成等价的字符(注意这里x,y和字符'x', 'y'不是一样的,只是个代号)。注意,等价关系是有传递性的。比如小A让'a'和'b'等价, 'b'和'c'等价,那么'a'和'c'等价。
对于两个长度字符串P,Q是等价的,当且仅当对于每一位,P的字符和Q的字符都是等价的。
小A希望你告诉他,要怎么利用好这K次机会(当然可以不用完),使得尽可能多对字符串是等价的。注意每对字符串只能算一次。
普及组考斯特林数...我可能真的只适合去玩泥巴
当k大于7时我们可以把图连成一棵树也就是全部匹配。
穷举匹配情况时间爆炸,所以枚举的是联通情况是为(8,8-K),在可以接受的范围内。
由于字符串长度很大,check答案还是会超时,所以Hash掉每个字母的出现情况一起判断即可
D2
T1
链接:A
小N得到了一个非常神奇的序列A。这个序列长度为N,下标从1开始。A的一个子区间对应一个序列,可以由数对[l,r]表示,代表A[l], A[l + 1], ..., A[r]这段数。对于一个序列B[1], B[2], ..., B[k],定义B的中位数如下:
先对B排序。得到新的序列C。
假如k是奇数,那么中位数为。假如k为偶数,中位数为。
对于A的所有的子区间,小N可以知道它们对应的中位数。现在小N想知道,所有长度>=Len的子区间中,中位数最大可以是多少。
一开始打算打60分的平衡树偏分来着...突然想到似乎可以二分?
由于中位数大小其实并不具有单调性(比如最小数在k>1的情况下无论如何也不会是中位数..)但是可行性还是单调的,每次check一个二分到的值\(x\)时把所有大于等于\(x\)的数全部赋值为1,小于\(x\)的数全部赋值为\(-1\)维护一个前缀和然后穷举每一个区间右端点然后找到长度大于等于k的最小值左端点,若相减只差大于0则最终答案肯定在\(x\)或\(x\)以上,否则则在\(x\)以下。
考试时写的愚蠢代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define update(now) c[now]=min(c[now*2],c[now*2+1])
using namespace std;
int i,m,j,k,a[100001],t[100001],pre[100001],maxx,c[500001],d[100001],e[100001],n,g[100001],w[100001];
void built(int now,int l,int r)
{
if(l==r) {c[now]=e[l]; return ;}
int mid=(l+r)>>1;
built(now*2,l,mid);
built(now*2+1,mid+1,r);
update(now);
}
int cha(int now,int l,int r,int rr)
{
int ans=0x3f3f3f3f;
if(r<=rr) return c[now];
int mid=(l+r)/2;
if(mid+1<=rr) ans=min(ans,cha(now*2+1,mid+1,r,rr));
ans=min(ans,cha(now*2,l,mid,rr));
return ans;
}
bool pan(int x)
{
memset(c,0x3f,sizeof(c));
memset(g,0,sizeof(g));
memset(w,0,sizeof(w));
e[0]=0;
for(int i=1;i<=n;i++)
{
if(a[i]>x) d[i]=1,g[i]=g[i-1];
else if(a[i]==x) d[i]=0, g[i]=i;
else d[i]=-1,g[i]=g[i-1];
e[i]=e[i-1]+d[i];
}
built(1,0,n);
for(int i=k;i<=n;i++)
if(e[i]-cha(1,0,n,i-k+1)>0) return 1;
for(int i=k;i<=n;i++)
if(g[i]) if(e[i]-cha(1,0,n,min(i-k,g[i]))>=0) return 1;
return 0;
}
int ef(int l,int r)
{
while(l<r)
{
int mid=(l+r+1)/2;
if(mid==36)
{
mid=36;
}
if(pan(mid)) l=mid;
else r=mid-1;
}
return l;
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%d",&a[i]),t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+1+n)-t-1;
for(int i=1;i<=n;i++)
{
int z=lower_bound(t+1,t+1+m,a[i])-t;
pre[z]=a[i]; a[i]=z;
maxx=max(maxx,a[i]);
}
printf("%d",pre[ef(1,maxx)]);
}
然鹅不用啊,最小值是单调的....
修改后
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int i,m,j,k,a[100001],maxx,c[500001],d[100001],e[100001],n,tmp;
bool pan(int x)
{
for(int i=1;i<=n;i++)
{
if(a[i]>=x) e[i]=e[i-1]+1;
else e[i]=e[i-1]-1;
}
int p=0x3f3f3f3f;
for(int i=k;i<=n;i++)
{
p=min(p,e[i-k]);
if(e[i]-p>0) return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%d",&a[i]),maxx=max(maxx,a[i]);
int l=1, r=maxx;
while(l<=r)
{
int mid=(l+r)/2;
if(pan(mid)) tmp=mid,l=mid+1;
else r=mid-1;
}
printf("%d",tmp);
}
T2
链接:B
小N对于数字的大小一直都有两种看法。第一种看法是,使用字典序的大小(也就是我们常用的判断数字大小的方法,假如比较的数字长度不同,则在较短一个前面补齐前导0,再比较字典序),比如43<355,10<11。第二种看法是,对于一个数字,定义他的权值为,也就是各个数位的乘积。
现在给定两个区间,[L,R]与[L1,R1]。小N现在想知道,有多少使用字典序判大小法在[L,R]之间的数字,满足其第二种定义的权值也在[L1,R1]之间。
换句话说,对于一个数x,定义f(x)为x的各个数位的乘积。对于L<=x<=R,问有多少x满足,L1<=f(x)<=R1。
恶意拉长题目描述差评
45分暴力很好啊QWQ
正解
数位dp,把情况分为两种,包含0和不包含0,然后包含0为至少含有1个0的情况,特判即可。
不包含0
把\(L1,R1\)质因数分解,由于每一位都\(\in[x|9\leq x\leq1]\)所以分解出的质因数也只有\(2,3,5,7\)四个且都不会超过60个。然后就是数位dp
T3
链接:C
来源:牛客网
C国有n个城市,城市间通过一个树形结构形成一个连通图。城市编号为1到n,其中1号城市为首都。国家有m支军队,分别守卫一条路径的城市。具体来说,对于军队i,他守卫的城市区域可以由一对二元组(xi,yi)代表。表示对于所有在xi到yi的最短路径上的城市,军队i都会守卫他们。
现在有q个重要人物。对于一个重要人物j,他要从他的辖区vj出发,去到首都。出于某些原因,他希望找到一个离首都最近的,且在vj到首都路径上的城市uj,使得至少有kj支军队,能够全程保护他从vj到uj上所经过的所有城市。换句话说,至少有ki支军队,满足在树上,xi到yi的路径能完全覆盖掉vj到uj的路径。
一看就是万恶的数据结构题...(咕咕咕
练习赛28
链接:D
来源:牛客网
题目描述
n个字符串q次询问,每次询问n个字符串去掉\(k_i\)的所有情况剩下的字符串两两间前缀相同最大长度和。
\(N\leq 4000,Q\leq 200,\sum|S|\leq3000000,k\leq300\).
其实每两个字符串的最长前缀在答案中的出现次数一定是一样的,所以答案一定是sum前缀的倍数
考虑答案中一共出现了几个lcp
\[\frac{C_n^k\times C_{n-k}^2}{C_n^2}\times sum\]
\[=C_{n-2}^k\times sum\]
wzx神仙一下就想到了第二个柿子ORZ ORZ ORZORZ
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define M 1000000007
#define LL long long
#define re register
#define maxn 3000005
#define max(a,b) ((a)>(b) ? (a): (b))
using namespace std;
LL i,m,n,j,k,A[1000001],B[1000001],inv[1000001],z,x,y,q;
LL cnt;
LL son[maxn][26];
char S[maxn];
LL flag[maxn],sum[maxn],deep[maxn];
LL ans=0;
inline void ins()
{
scanf("%s",S+1);
int L=strlen(S+1);
int now=0;
for(re int i=1;i<=L;i++)
{
if(!son[now][S[i]-'a']) son[now][S[i]-'a']=++cnt;
sum[son[now][S[i]-'a']]++;
ans=(ans+(sum[now]-sum[son[now][S[i]-'a']])*(i-1))%M;
now=son[now][S[i]-'a'];
}
ans=(ans+L*(sum[now]-1))%M;
}
int main()
{
scanf("%lld%lld",&n,&q);
inv[1]=A[1]=B[1]=1;
A[0]=B[0]=inv[0]=1;
for(i=2;i<=n;i++)
{
inv[i]=(M-M/i)*inv[M%i]%M;
B[i]=(LL)B[i-1]*(LL)inv[i]%M;
A[i]=(LL)A[i-1]*i%M;
}
for(re LL i=1;i<=n;i++) ins();
for(i=1;i<=q;i++)
{
scanf("%lld",&k);
printf("%lld\n",(LL)A[n-2]%M*B[k]%M*B[n-k-2]%M*ans%M);
}
}
普及组R4
T3
链接:C
输入一个长度为n的数组a[i],下标从0开始(0到n-1)
保证n是2的整数次幂,
对于每个i (0 <= i < n)
求所有满足((i & j) == j)的a[j]之和。
对于100%的数据,1 <= n <= \(2^{20}\), 0 <= a[i] <= 1000
三维部分区间和
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
a[i][j][k] += a[i][j][k - 1] + a[i][j - 1][k] + a[i - 1][j][k];
a[i][j][k] -= a[i][j - 1][k - 1] + a[i - 1][j - 1][k] + a[i - 1][j][k - 1];
a[i][j][k] += a[i - 1][j - 1][k - 1];
}
}
}
或如下代码
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
a[i][j][k] += a[i][j][k - 1];
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
a[i][j][k] += a[i][j - 1][k];
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
a[i][j][k] += a[i - 1][j][k];
}
}
}
题目好评↑
推广一下到20维
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define max(a,b) ((a)>(b) ? (a): (b))
#define RI register int
using namespace std;
int i,m,n,j,k,a[2000001],g;
int main()
{
scanf("%d",&n);
for(RI i=0;i<n;i++) scanf("%d",&a[i]);
m=n; g=0;
while(m)
{
m>>=1;
g+=1;
}
for(RI i=0;i<g;i++)
for(RI j=(1<<i);j<n;j++)
if(j&(1<<i)) a[j]+=a[j-(1<<i)];
for(RI i=0;i<n;i++) printf("%d\n",a[i]);
}
T4
链接:D
用L图形(大小为3,也就是去掉一个角的2x2的正方形)和1x2的矩形,覆盖2xn的矩形,问有多少种方案。
覆盖要求不重不漏,整体翻转和旋转均算作不同的方案。
用于覆盖的图形可以旋转,比如可以把L旋转为Г,把1x2的矩形旋转成为2x1的矩形等。
输出方案数模10007的结果。
对于100%的数据,\(1 <= n <= 10^{100000}\)
欧拉定理可证\(x^n\equiv x^{n\%\varphi(m)}(\%m)\)
由于10007是质数,所以\(\varphi(10007)=10006\)
所以高精模后dp来做就好啦
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define M 10007
#define max(a,b) ((a)>(b) ? (a): (b))
using namespace std;
int i,m,n,j,k,a[100001][3];
char c[200001];
int qm(char *c,int k)
{
int s=strlen(c);
int m=0;
for(int i=0;i<s;i++) m=m*10+c[i]-'0', m%=k;
return m%k;
}
int main()
{
gets(c);
n=qm(c,10006);
a[0][0]=1;
for(i=1;i<=n;i++)
{
if(i>1) a[i][0]+=a[i-2][0];
a[i][0]=(a[i][0]+a[i-1][0]+a[i-1][1]+a[i-1][2])%M;
if(i>1) a[i][1]+=a[i-2][0];
a[i][1]=(a[i][1]+a[i-1][2])%M;
if(i>1) a[i][2]+=a[i-2][0];
a[i][2]=(a[i][2]+a[i-1][1])%M;
}
printf("%d",a[n][0]);
}
Wannafly挑战赛27
于是说好带我上分拿购物卡的asuldb神仙自己咕咕掉分了
还好我rateing低 ~(~ ̄▽ ̄)~
链接:B
来源:牛客网
给出一棵仙人掌(每条边最多被包含于一个环,无自环,无重边,保证连通),要求用最少的颜色对其顶点染色,满足每条边两个端点的颜色不同,输出最小颜色数即可
结论:ans=1/2/3
没有边ans=1, 没有三角形ans=2,否则ans=3
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define max(a,b) ((a)>(b)? (a):(b))
#define min(a,b) ((a)<(b)? (a):(b))
using namespace std;
int i,m,n,j,k,a[1000001],ver[1000001],edge[1000001],nex[1000001],cnt,d[1000001],head[1000001],x,y;
void add(int x,int y)
{
cnt+=1;
ver[cnt]=y; nex[cnt]=head[x]; head[x]=cnt;
}
bool dfs(int now)
{
for(int i=head[now];i;i=nex[i])
{
int t=ver[i];
if(d[t]==d[now]) return 0;
if(!d[t])
{
d[t]=d[now]%2+1;
if(!dfs(t)) return 0;
}
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
if(n==0)
{
printf("0");
return 0;
}
if(m==0)
{
printf("1");
return 0;
}
d[1]=1;
if(dfs(1)) printf("2");
else printf("3");
}
链接:C
来源:牛客网
给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一条边在一个方案中被删除,而在另一个方案中未被删除,答案对998244353取模
卡常!卡常!!卡常!!!严重卡常!!!!!
这是第一次提交能跑出正解
然后
写题1h卡常1.5h
所以这个sxbk的程序张这样
#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
#define M 998244353
#define RI register int
#define max(a,b) ((a)>(b)? (a):(b))
#define min(a,b) ((a)<(b)? (a):(b))
using namespace std;
int m,n,k,f[2001][2001], head[4001], nex[4001], ver[4001], cnt,s[4001],x,y,ans;
inline void add(int x,int y)
{
cnt+=1;
ver[cnt]=y; nex[cnt]=head[x]; head[x]=cnt;
}
inline char gc()
{
static char now[1<<22],*S,*T;
if (T==S)
{
T=(S=now)+fread(now,1,1<<22,stdin);
if (T==S) return EOF;
}
return *S++;
}
inline int read()
{
register int x=0,f=1;
register char ch=gc();
while(!isdigit(ch))
{
if (ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=gc();
return x*f;
}
void dfs(int now,int fa)
{
s[now]=1;
f[now][1]=1;
for(RI i=head[now];i;i=nex[i])
{
int t=ver[i];
if(t==fa) continue;
dfs(t,now);
s[now]+=s[t];
for(RI j=min(s[now],k);j>0;--j)
{
if(f[t][0]!=0 &&f[t][0]!=1) f[now][j]=((LL)f[now][j]*f[t][0])%M;
if(j==1) continue;
for(RI l=1;l<=min(s[t],j-1);++l)
{
if(f[now][j-l]==0 || f[t][l]==0) continue;
int o=(LL)f[now][j-l]*f[t][l]%M;
if(f[now][j]+o<M) f[now][j]=(f[now][j]+o);
else f[now][j]=f[now][j]+o-M;
}
}
}
for(RI i=1;i<=min(s[now],k);++i)
{
if(!f[now][i]) break;
if(f[now][0]+f[now][i]<M) f[now][0]=f[now][0]+f[now][i];
else f[now][0]=(f[now][0]+f[now][i])-M;
}
}
int main()
{
n=read(); k=read();
for(RI i=1;i<n;++i)
{
x=read(); y=read();
add(x,y); add(y,x);
}
dfs(1,0);
printf("%d",f[1][0]);
}
牛客网NOIP赛前集训营-普及组(第七场)
链接:C
来源:牛客网
牛牛的同学给牛牛表演了一个读心术:牛牛先任意选定一个非负整数,然后进行N次操作:每次操作前,假设牛牛当前的数是a,那么这个操作可能是a = a + x, 或者a = a * x, 或者a = a % x。N轮操作结束后,牛牛的同学成功猜出了牛牛最终的结果。牛牛觉得十分神奇,他现在把N个操作记录了下来,希望你帮忙验证一下这个读心术是不是一定会成功(既无论牛牛最开始选定的是什么数,最终的结果都是一样的)。
哇!这题可以乱搞!!!
然后我的乱搞就gg了TAT
然后正解也真的是乱搞,只是我搞丑了QAQ
显然最有用的是%,每次加完乘完后%一下下一个模数,至于最后一个模数后的数其实也没有什么用了
然后把1~100000暴力带进去试就行啦
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<ctime>
#include<cstring>
#define M 10000007
#define ULL unsigned long long
#define max(a,b) ((a)>(b)? (a):(b))
#define min(a,b) ((a)<(b)? (a):(b))
using namespace std;
ULL i,m,n,j,k,a[1000001][2],t,ans,b,c[100001], pre;
int main()
{
srand(time(0));
cin>>t;
for(;t;t--)
{
cin>>n;
pre=0;
for(i=1;i<=n;i++) cin>>a[i][0]>>a[i][1];
for(i=n;i>=1;i--)
{
if(a[i][0]==2) pre=a[i][1];
if(!pre) n--;
else c[i]=pre;
}
for(i=0,b=1;i<=10;i++)
{
ULL k=i;
for(j=1;j<=n;j++)
{
if(a[j][0]==0) k=k+a[j][1]%c[j];
if(a[j][0]==1) k=k*a[j][1]%c[j];
if(a[j][0]==2) k=k%a[j][1];
}
if(i==0) ans=k;
else if(ans!=k)
{
b=0;
break;
}
}
if(!b)
{
printf("NO\n");
continue;
}
for(i=0,b=1;i<=1000;i++)
{
ULL k=rand();
for(j=1;j<=n;j++)
{
if(a[j][0]==0) k=(k+a[j][1])%c[j];
if(a[j][0]==1) k=(k*a[j][1])%c[j];
if(a[j][0]==2) k=(k%a[j][1]);
}
if(ans!=k)
{
b=0;
break;
}
}
if(!b) printf("NO\n");
else printf("YES\n");
}
}
牛客网NOIP赛前集训营-提高组(第七场)
链接:B
来源:牛客网
牛牛在纸上画了N个点(从1到N编号),每个点的颜色用一个整数描述。牛牛决定用这N个点随机生成一棵树,生成的规则如下:
1、1号点是根节点
2、对于2号点到N号点,每个点随机指定一个父亲。i号点(2 <= i <= N)的父亲在i的约数中随机挑选一个。(例如10号点的父亲可以是1号,2号,5号,7号点的父亲只能是1号点)
树生成完之后,牛牛可以计算出这个树有多少个联通块,一个联通块是一些点的集合,需要满足以下两个条件:
1、从集合中任取两个点都满足:两个点颜色相同,且这两个点之间存在一条树边组成的路径,路径上的所有点都和这两个点颜色相同
2、对于集合中的任意一个点和集合外的任意一个点:两点要么不同色,要么不存在一条树边组成的路径使得路径上所有点都和这两个点同色。
牛牛希望计算出生成的树中最多有多少个联通块
简单来说就是看看每个数的约数有没有颜色和它不一样的
暴力可过,欧拉筛由于没有筛到最小质因和其他因子乘积子并不可过
链接:C
来源:牛客网
有一天,牛牛找到了一个巨大的洞穴。洞穴可以描述成一个有向图,一共有N个节点(从1到N编号)和M条长度为1的有向边,每条边从某一个节点u连向另一个节点v(u可能等于v)。
为了更好的探索洞穴,牛牛向你提出了Q个问题,每个问题给定两个节点a, b以及一个数l, 你需要告诉牛牛是否存在一条开始于a, 结束于b的路径,总长度为l。(路径中可以经过任意点、边多次,但只能沿着单向边给定的方向行走,不允许反向行走)。
离线矩阵T飞了,正解是倍增+floyd
咕咕咕