21杭电多校第一场
A
签到题,显然可以取到所有\(<\lceil\frac{n}{2}\rceil\)的所有数,则答案就是\(n-1\)的最高位\(2^x-1\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll n,T;
int main()
{
rep(T,1,read())
{
n=read();
ll p=1;while(p<n) p*=2;
p/=2;printf("%lld\n",max(p-1,0LL));
}
}
B
\(kd-tree\)暴力查询,记录一下子树内的权值和,每次修改的时候由下至上更新
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 200100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,xx[MAXN],yy[MAXN],w[MAXN],id[MAXN],rr[MAXN],Dim;
inline ll sqr(ll x){return x*x;}
struct node {int mx[2],mn[2],d[2],l,r,id;ll sum,w;};
bool operator < (const node a,const node b) {return a.d[Dim]<b.d[Dim];}
struct kd_tree
{
int Rt,fa[MAXN];node tr[MAXN],l,r;
void upd(int k)
{
l=tr[tr[k].l],r=tr[tr[k].r];
rep(i,0,1)
{
if(tr[k].l)
tr[k].mx[i]=max(tr[k].mx[i],l.mx[i]),tr[k].mn[i]=min(tr[k].mn[i],l.mn[i]);
if(tr[k].r)
tr[k].mx[i]=max(tr[k].mx[i],r.mx[i]),tr[k].mn[i]=min(tr[k].mn[i],r.mn[i]);
}
}
int build(int l,int r,int now)
{
int mid=l+r>>1;Dim=now;nth_element(tr+l,tr+mid,tr+r+1);
rep(i,0,1) tr[mid].mn[i]=tr[mid].mx[i]=tr[mid].d[i];
id[tr[mid].id]=mid;
if(l<mid) tr[mid].l=build(l,mid-1,now^1),fa[tr[mid].l]=mid;
if(mid<r) tr[mid].r=build(mid+1,r,now^1),fa[tr[mid].r]=mid;
upd(mid);return mid;
}
void mdf(int k,int w)
{
tr[k].w=w;tr[k].sum+=w;
for(k=fa[k];k;k=fa[k]) tr[k].sum+=w;
}
void init()
{
rep(i,1,n)
{
tr[i].id=i,tr[i].l=tr[i].r=fa[i]=tr[i].sum=tr[i].w=0;
xx[i]=tr[i].d[0]=read(),yy[i]=tr[i].d[1]=read();
w[i]=read(),rr[i]=read();
}
Rt=build(1,n,0);
}
inline int ok(int cx,int cy,int R,int a,int b)
{
return sqr(a-cx)+sqr(b-cy)<=sqr(R);
}
inline int in(int cx,int cy,int R,int x1,int y1,int x2,int y2)
{
if(!ok(cx,cy,R,x1,y1)) return 0;
if(!ok(cx,cy,R,x1,y2)) return 0;
if(!ok(cx,cy,R,x2,y1)) return 0;
if(!ok(cx,cy,R,x2,y2)) return 0;
return 1;
}
inline int out(int cx,int cy,int R,int x1,int y1,int x2,int y2)
{
int a,b;
if(x1<=cx&&cx<=x2) a=cx;
else if(cx<x1) a=x1;else a=x2;
if(y1<=cy&&cy<=y2) b=cy;
else if(cy<y1) b=y1;else b=y2;
if(ok(cx,cy,R,a,b)) return 0;
else return 1;
}
ll query(int k,int x,int y,int R,ll res=0)
{
if(!tr[k].sum) return 0;
if(in(x,y,R,tr[k].mn[0],tr[k].mn[1],tr[k].mx[0],tr[k].mx[1]))
return tr[k].sum;
if(out(x,y,R,tr[k].mn[0],tr[k].mn[1],tr[k].mx[0],tr[k].mx[1]))
return 0;
if(ok(x,y,R,tr[k].d[0],tr[k].d[1])) res=tr[k].w;
if(tr[k].l) res+=query(tr[k].l,x,y,R);
if(tr[k].r) res+=query(tr[k].r,x,y,R);
return res;
}
void solve()
{
rep(i,1,n)
{
printf("%lld\n",query(Rt,xx[i],yy[i],rr[i])+w[i]);
mdf(id[i],w[i]);
}
}
}kd;
int main()
{
rep(T,1,read())
{n=read();kd.init();kd.solve();}
}
C
将每个边是否选表示为一个\(0/1\)变量,用异或方程表示限制,则答案为\(2^k\)其中\(k\)为自由元个数
则题目中所有环没有公共边只有公共点,可以表示为和一个节点相邻的边数为偶数
每个方块周围边数的奇偶性也同样可以表示
可以用\(bitset\)加速这个异或方程的高斯消元求解过程
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,tot,idx[20][20],idy[20][20],cnt,ans;
char s[20];
bitset<700> a[700];
int main()
{
int now,pos;rep(T,1,read())
{
n=read()-1,m=read()-1;tot=cnt=0;ans=-1;
rep(i,1,n+1) rep(j,1,m) idx[i][j]=++tot;
rep(i,1,n) rep(j,1,m+1) idy[i][j]=++tot;
rep(i,1,n+1) rep(j,1,m+1)
{
a[++cnt].reset();
if(i>1) a[cnt][idy[i-1][j]]=1;
if(j>1) a[cnt][idx[i][j-1]]=1;
if(i<=n) a[cnt][idy[i][j]]=1;
if(j<=m) a[cnt][idx[i][j]]=1;
}
rep(i,1,n)
{
scanf("%s",s+1);
rep(j,1,m) if(s[j]!='.')
{
a[++cnt].reset();a[cnt][tot+1]=s[j]-'0';
a[cnt][idx[i][j]]=a[cnt][idy[i][j]]=1;
a[cnt][idx[i+1][j]]=a[cnt][idy[i][j+1]]=1;
}
}
n=tot,m=cnt;now=1,pos;
rep(i,1,n)
{
pos=0;rep(j,now,m) if(a[j][i]) {pos=j;break;}
if(!pos) continue;
if(pos!=now) swap(a[pos],a[now]);
rep(j,now+1,m) if(a[j][i]) a[j]^=a[now];
now++;
}
rep(i,now,m) if(a[i].any()) {ans=0;break;}
if(~ans) {puts("0");continue;}
ans=1;rep(i,now,n) ans=mul(ans,2);
printf("%d\n",ans);
}
}
D
设\(f(i,j)\)表示前\(j\)个物品总价值为\(i\)的方案数,则有
最好将上面的向下取整扔掉,考虑将\(i\)写成\(k\cdot LCM+r\)的形式,其中\(r=k'a_j+q\)则
可以证明\(f(k\cdot LCM+r,j)\)为关于\(k\)的\(j-1\)次多项式,记为\(F_{j,r}\)即\(f(k\cdot LCM+r,j)=F_{j,r}(k)\)
因此可以暴力\(dp\)出前\(n\cdot LCM\)项的\(f(i,n)\)值,复杂度\(O(n^2LCM)\)
取出余数相同的\(f\)作为\(F_{n,r}\)的\(n\)个函数点值,使用拉格朗日插值即可求出\(F_{n,r}(k)\)
拉格朗日插值的构造非常暴力,设\(F(x)=\sum\limits_{i=1}^nf_i(x)\),其中\(f_i(x)\)表示只满足\((x_i,y_i)\),其余\(y|_{x=x_j}=0\)的函数
令\(f_i(x)=y_i\frac{\prod_{i\neq j}x-x_j}{\prod_{i\neq j}x_i-x_j}\)即符合条件
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 300100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a[120],lcm,inv[120],f[MAXN],y[120];ll k;
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int Lagrange(ll x,int res=0)
{
int tmp;x%=MOD;rep(i,1,n)
{
tmp=1;
rep(j,1,i-1) tmp=mul(tmp,inv[i-j]);
rep(j,i+1,n) tmp=mul(tmp,-inv[j-i]);
rep(j,1,n) if(i!=j) tmp=mul(tmp,x-j);
tmp=mul(tmp,y[i]);
res=pls(res,tmp);
}
return (res+MOD)%MOD;
}
int main()
{
inv[0]=inv[1]=1;rep(i,2,105) inv[i]=mul(inv[MOD%i],(MOD-MOD/i));
int x,g;rep(T,1,read())
{
n=read(),k=read();lcm=1;
rep(i,1,n) a[i]=read(),g=gcd(lcm,a[i]),lcm=lcm/g*a[i];
f[0]=1;rep(i,1,n*lcm) f[i]=0;
rep(i,1,n) rep(j,a[i],n*lcm) f[j]=pls(f[j],f[j-a[i]]);
if(k<=n*lcm) {printf("%d\n",f[k]);continue;}
rep(i,0,n-1) y[i+1]=f[k%lcm+i*lcm];
printf("%d\n",Lagrange(k/lcm+1));
}
}
E
签到题,每个合数\(i\)可以向他们的约数连边,贡献为\(i\);每个素数\(p\)可以和\(2\)连边,贡献为\(2p\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 10010010
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,p[MAXN/7],tot,ntp[MAXN];ll ans[MAXN];
void mem(int n=1e7)
{
rep(i,2,n)
{
if(!ntp[i]) p[++tot]=i;
rep(j,1,tot) if(i*p[j]>n) break;
else {ntp[i*p[j]]=1;if(i%p[j]==0) break;}
}
rep(i,3,n) ans[i]=ans[i-1]+(ntp[i]?i:2*i);
}
int main()
{
mem();
rep(T,1,read()) printf("%lld\n",ans[read()]);
}
F
转化为前缀和后,问题变为查找最近的两个数使得他们的异或和\(\ge k\)
从左到右加入每个前缀和,对\(trie\)树上的每个节点记录经过这个点的最大编号
对每个右端点\(r\),在查询的时候按照\(k \otimes sum_r\)在\(trie\)树上遍历
若该位为\(0\)则\(1\)的子树内所有数都符合条件,选出最大值;其余情况就一直沿着\(trie\)树走到底再查询
每次查询后更新答案
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,k,tr[MAXN*30][2],tot,g[30],mx[MAXN*30],ansl,ansr,ans=inf;
void ins(int x,int id)
{
int t,res=-1,p=0;dwn(i,29,0)
{
t=(x>>i)&1;
if(!g[i])
{
if(tr[p][t^1]) {res=max(res,mx[tr[p][1^t]]);break;}
if(tr[p][t]) p=tr[p][t],res=mx[p];
}
else
{
if(tr[p][t^1]) p=tr[p][t^1],res=mx[p];
else {res=-1;break;}
}
}
//cout<<id<<" "<<res<<endl;
if(~res) if(id-res<ans) ans=id-res,ansl=res+1,ansr=id;
p=0;dwn(i,29,0)
{
t=(x>>i)&1;if(!tr[p][t]) tr[p][t]=++tot;
p=tr[p][t],mx[p]=id;
}
}
int main()
{
rep(T,1,read())
{
n=read(),k=read();int s=0;tot=0;ans=inf;
dwn(i,29,0) if(k&(1<<i)) g[i]=1;else g[i]=0;
ins(s,0);rep(i,1,n) {s^=read();ins(s,i);}
if(ans!=inf) printf("%d %d\n",ansl,ansr);
else puts("-1");
dwn(i,tot,0) tr[i][0]=tr[i][1]=0;
}
}
G
令\(f_i\)表示一共\(n\)个人的时候第\(i\)轮传回自己的方案数
由于传\(i\)次球的总方案数为\((n-1)^i\),其中\(f_i\)种对应此时球在自己手中的情况,而剩余的\((n-1)^i-f_i\)种由于再传一次可以传回自己,则这些方案和\(f_{i+1}\)形成了一一对应,即\(f_i+f_{i+1}=(n-1)^i\)
由于\(f_1=0\),可以看出\(f_i=(n-1)^{i-1}-(n-1)^{i-2}+\cdots +(-1)^{i-2}(n-1)\)
给出\(f_i\equiv t\ (mod\ P)\),即:
需要对\(i\)进行奇偶性讨论分别计算
-
当\(i\)为奇数时,\(\frac{nt}{n-1}\equiv -[1-(n-1)^{i-1}]\ (mod\ P)\)即\(\lgroup\frac{nt}{n-1}+1\rgroup(n-1)\equiv (n-1)^i\ (mod\ P)\)
-
当\(i\)为奇数时,\(\frac{nt}{n-1}\equiv 1-[-(n-1)^{i-1}]\ (mod\ P)\)即\(\lgroup\frac{nt}{n-1}-1\rgroup(n-1)\equiv (n-1)^i\ (mod\ P)\)
均转化为了\(bsgs\)的形式,套板子之后求解即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct HashTable
{
const int mod=100007;
int fst[MAXN],key2[MAXN],nxt[MAXN],tot;
ll key1[MAXN];
inline void mem(){memset(fst,0,sizeof(fst));tot=0;}
void ins(ll k1,int k2)
{
int hsh=(int)k1%mod;
key1[++tot]=k1,key2[tot]=k2;
nxt[tot]=fst[hsh],fst[hsh]=tot;
}
int find(ll k1)
{
int hsh=(int)k1%mod;
for(int i=fst[hsh];i;i=nxt[i])
if(key1[i]==k1) return key2[i];
return -1;
}
}hsh;
int qp(int x,int t,int res=1)
{
for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);
return res;
}
#define inv(x) qp(x,MOD-2)
int bsgs(int y,int z)
{
int ok=0;hsh.mem();
if(!(y%MOD)) {return -1;}
ll m=ceil(sqrt(MOD)),a=1ll,res;
for(int i=0;i<=m;i++)
hsh.ins(a*z%MOD,i),(a*=y)%=MOD;
a=1ll,res=qp(y,m);
for(int i=1,t;i<=m;i++)
{
(a*=res)%=MOD,t=hsh.find(a);
if(t!=-1) return ((m*i-t)%MOD+MOD)%MOD;
}
return -1;
}
int n,x,ans1,ans2,ans;
int main()
{
int t;rep(T,1,read())
{
n=read(),x=read();
x=mul(x,mul(n,inv(n-1)));
t=mul(pls(x,1),n-1);ans1=bsgs(n-1,t);//odd
t=mul(mns(x,1),n-1);ans2=bsgs(n-1,t);//even
if(ans1!=-1&&ans1%2==0) ans1=-1;
if(ans2!=-1&&(ans2&1)) ans2=-1;
ans=min(ans1,ans2);
if(ans==-1) ans=max(ans1,ans2);
printf("%d\n",ans);
}
}
H
预处理每个点向下最远不降到哪
枚举矩形横着的边,可以用单调栈处理出这一行每个点左右第一个下降距离比它小的点
则这个点的答案即为\((r-l-1)*dis_i\),每个点都更新答案即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 2020
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,g[MAXN][MAXN],mx[MAXN][MAXN],ans,l[MAXN],r[MAXN],s[MAXN],tp;
int main()
{
rep(T,1,read())
{
n=read(),m=read();ans=0;
rep(i,1,n) rep(j,1,m) g[i][j]=read(),mx[i][j]=0;
rep(j,1,m) rep(i,1,n) if(g[i][j]>g[i+1][j]||i==n) mx[i][j]=i;
rep(j,1,m) dwn(i,n,1) if(!mx[i][j]) mx[i][j]=mx[i+1][j];
rep(i,1,n)
{
tp=0;rep(j,1,m)
{
while(tp&&mx[i][s[tp]]>=mx[i][j]) tp--;
if(tp) l[j]=s[tp];else l[j]=0;s[++tp]=j;
}
tp=0;dwn(j,m,1)
{
while(tp&&mx[i][s[tp]]>=mx[i][j]) tp--;
if(tp) r[j]=s[tp];else r[j]=m+1;s[++tp]=j;
}
rep(j,1,m) ans=max(ans,(r[j]-l[j]-1)*(mx[i][j]-i+1));
}
printf("%d\n",ans);
}
}
I
根据题意,需要求是否存在\(D\)使得将\(\le D\)的所有边加入后, 图上有\(K\)个联通块
将边排序后,按照顺序加边并查集判断
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 500100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct Edge{int u,v,w;}e[MAXN];
bool operator < (Edge a,Edge b){return a.w<b.w;}
int n,m,k,fa[MAXN],tot,ans;
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void merge(int u,int v){int fu=find(u),fv=find(v);if(fu!=fv) fa[fu]=fv,tot--;}
int main()
{
rep(T,1,read())
{
scanf("%d%d%d",&n,&m,&k);rep(i,1,n) fa[i]=i;tot=n;ans=-1;
rep(i,1,m) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
if(n==k) {puts("0");continue;}sort(e+1,e+m+1);
rep(i,1,m)
{
merge(e[i].u,e[i].v);
if(tot<k) break;
if((e[i].w!=e[i+1].w||i==m)&&tot==k) {ans=e[i].w;break;}
}
printf("%d\n",ans);
}
}
J
莫队+树状数组暴力跑的非常快
用树状数组维护当前区间里的数,外面套莫队即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int lim=1e5;
int n,m,g[MAXN],bl[MAXN],sz,c[MAXN];
int ans[MAXN],res,w[MAXN];
struct ask{int l,r,a,b,id;}q[MAXN];
inline void mdf(int x,int w) {if(!x) return ;for(;x<=lim;x+=x&-x) c[x]+=w;}
inline int query(int x,int res=0) {if(!x) return 0;for(;x;x-=x&-x) res+=c[x];return res;}
bool cmp(ask a,ask b){return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);}
int main()
{
rep(T,1,read())
{
Fill(c,0);Fill(w,0);
n=read(),sz=sqrt(n);m=read();rep(i,1,n) g[i]=read()+1,bl[i]=(i-1)/sz;g[n+1]=n+1;
rep(i,1,m) q[i].l=read(),q[i].a=read()+1,q[i].r=read(),q[i].b=read()+1,q[i].id=i;
sort(q+1,q+m+1,cmp);int l=0,r=0;rep(i,1,m)
{
while(l<q[i].l) {w[g[l]]--;if(w[g[l]]==0) mdf(g[l],-1);l++;}
while(l>q[i].l) {l--;w[g[l]]++;if(w[g[l]]==1) mdf(g[l],1);}
while(r>q[i].r) {w[g[r]]--;if(w[g[r]]==0) mdf(g[r],-1);r--;}
while(r<q[i].r) {r++;w[g[r]]++;if(w[g[r]]==1) mdf(g[r],1);}
ans[q[i].id]=query(q[i].b)-query(q[i].a-1);
}
rep(i,1,m) printf("%lld\n",ans[i]);
}
}
L
这个题限制比较多,考虑\(burnside\)定理,对于旋转\(i\)这个置换,求解其不动点个数
有循环节个数\(=gcd(i,n)\)即需要考虑对一个长度为\(gcd(i,n)\)的环染色的方案
设\(F(i,j)\)表示长度为\(i\)的环染\(j\)个绿色且相邻颜色不同的方案数
可以先考虑将\(j\)个绿色先放在一些不相邻的位置,则剩余的连续空位显然只有两种填法
而\(j=0\)的时候根据\(i\)的奇偶性可能无解或有两种情况,也很显然
设\(G(i,j)\)表示长度为\(i\)的环选\(j\)个不相邻的位置的方案数,则\(F(i,j)=2^mG(n,m)\)
对于\(G(i,j)\)可以做一个简单的分类讨论
- 当\(n\)位置不被选中时,考虑将所有绿色与后面的一个空位捆绑考虑,则存在\(j\)个绿色块,\(i-2j\)个空位,方案为\(\binom{i-j}{j}\)
- 当选\(n\)时,\(1\)位置也一定不能选,可以不考虑\(1\)位置,将剩余的所有绿色与前面一个空位捆绑考虑,存在\(j-1\)个自由的绿色块,\(i-2-2(j-1)=i-2j\)个空位,方案为\(\binom{i-j-1}{j-1}\)
加和得到\(G(i,j)=\binom{i-j}{j}+\binom{i-j-1}{j-1}\)
预处理阶乘和\(2^k\)之后即可\(O(1)\)得到\(F(i,j)\)
现在考虑整个答案的计算:
因为每个循环的所有颜色应当一样,故\(j\cdot\frac{n}{gcd(n,i)}\le k\)即\(j\le \lfloor \frac{k\cdot gcd(n,i)}{n}\rfloor\)则有:
由于需要\(d\ge j\),否则\(F(d,j)\)没有意义,因此计算\(\sum_{j=0}^{\lfloor \frac{kd}{n}\rfloor}F(d,j)\)的时间复杂度至多为\(O(d)\)
而\(\sum\limits_{d|n} d=\sum\limits_{d|n}\frac{n}{d}\le \sum\limits_{i=1}^n \frac{n}{i} =nlogn\)
故可以直接枚举\(d\),暴力计算所有\(F(d,j)\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 1001001
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,k,ntp[MAXN],p[MAXN],tot,phi[MAXN],fac[MAXN],ifac[MAXN],pw2[MAXN],ans;
int qp(int x,int t,int res=1)
{
for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);
return res;
}
#define inv(x) qp(x,MOD-2)
void mem(int n=1e6)
{
phi[1]=1;rep(i,2,n)
{
if(!ntp[i]) p[++tot]=i,phi[i]=i-1;
rep(j,1,tot) if(p[j]*i>n) break;
else
{
ntp[i*p[j]]=1;
if(i%p[j]) phi[i*p[j]]=phi[i]*(p[j]-1);
else {phi[i*p[j]]=phi[i]*p[j];break;}
}
}
fac[0]=pw2[0]=1;rep(i,1,n) fac[i]=mul(fac[i-1],i),pw2[i]=mul(pw2[i-1],2);
ifac[n]=inv(fac[n]);dwn(i,n-1,0) ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(int n,int m)
{
if(n<m||n<0||m<0) return 0;
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
inline int F(int n,int k)
{
if(!k) return (n&1)?0:2;
return mul(pw2[k],pls(C(n-k,k),C(n-k-1,k-1)));
}
inline int sum(int n,int k,int res=0)
{
rep(i,0,min(n,k)) res=pls(res,F(n,i));
return res;
}
int main()
{
mem();rep(T,1,read())
{
n=read(),k=read();ans=0;
rep(i,1,sqrt(n)) if(n%i==0)
{
ans=pls(ans,mul(phi[n/i],sum(i,k*i/n)));
if(i*i!=n) ans=pls(ans,mul(phi[i],sum(n/i,k/i)));
}
printf("%d\n",mul(ans,inv(n)));
}
}