21杭电多校第一场

A

签到题,显然可以取到所有(<lceilfrac{n}{2} ceil)的所有数,则答案就是(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
",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
",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
",ans);
	}
}

D

(f(i,j))表示前(j)个物品总价值为(i)的方案数,则有

[f(i,j)=f(i,j-1)+f(i-a_j,j)=sumlimits_{t=0}^{lfloor frac{i}{a_j} floor}f(i-tcdot a_j,j-1) ]

最好将上面的向下取整扔掉,考虑将(i)写成(kcdot LCM+r)的形式,其中(r=k'a_j+q)

[f(kcdot LCM+r,j)=sumlimits_{t=0}^{kcdot LCM/a_j+k'}f(kcdot LCM+r-tcdot a_j,j-1) ]

可以证明(f(kcdot LCM+r,j))为关于(k)(j-1)次多项式,记为(F_{j,r})(f(kcdot LCM+r,j)=F_{j,r}(k))

因此可以暴力(dp)出前(ncdot LCM)项的(f(i,n))值,复杂度(O(n^2LCM))

取出余数相同的(f)作为(F_{n,r})(n)个函数点值,使用拉格朗日插值即可求出(F_{n,r}(k))


拉格朗日插值的构造非常暴力,设(F(x)=sumlimits_{i=1}^nf_i(x)),其中(f_i(x))表示只满足((x_i,y_i)),其余(y|_{x=x_j}=0)的函数

(f_i(x)=y_ifrac{prod_{i eq j}x-x_j}{prod_{i eq 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
",f[k]);continue;}
		rep(i,0,n-1) y[i+1]=f[k%lcm+i*lcm];
		printf("%d
",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
",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
",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_iequiv t (mod P)),即:

[egin{aligned} t&equiv (-1)^{i-2}(n-1)sumlimits_{i=0}^{i-2}[-(n-1)]^i (mod P)\ t&equiv (-1)^{i-2}(n-1)frac{1-[-(n-1)]^{i-1}}{1-[-(n-1)]} (mod P)\ frac{nt}{n-1}&equiv (-1)^{i-2}{1-[-(n-1)]^{i-1} } (mod P) end{aligned} ]

需要对(i)进行奇偶性讨论分别计算

  • (i)为奇数时,(frac{nt}{n-1}equiv -[1-(n-1)^{i-1}] (mod P))(lgroupfrac{nt}{n-1}+1 group(n-1)equiv (n-1)^i (mod P))

  • (i)为奇数时,(frac{nt}{n-1}equiv 1-[-(n-1)^{i-1}] (mod P))(lgroupfrac{nt}{n-1}-1 group(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
",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
",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
",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
",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)个空位,方案为(inom{i-j}{j})
  • 当选(n)时,(1)位置也一定不能选,可以不考虑(1)位置,将剩余的所有绿色与前面一个空位捆绑考虑,存在(j-1)个自由的绿色块,(i-2-2(j-1)=i-2j)个空位,方案为(inom{i-j-1}{j-1})

加和得到(G(i,j)=inom{i-j}{j}+inom{i-j-1}{j-1})

预处理阶乘和(2^k)之后即可(O(1))得到(F(i,j))

现在考虑整个答案的计算:

因为每个循环的所有颜色应当一样,故(jcdotfrac{n}{gcd(n,i)}le k)(jle lfloor frac{kcdot gcd(n,i)}{n} floor)则有:

[egin{aligned} ans&=frac{1}{n} sumlimits_{i=1}^n sum_{j=0}^{lfloor frac{kcdot gcd(n,i)}{n} floor}F(gcd(i,n),j)\ ans&=frac{1}{n} sumlimits_{d|n} sumlimits_{i=1}^nsum_{j=0}^{lfloor frac{kd}{n} floor}F(d,j)[(i,n)==d]\ ans&=frac{1}{n} sumlimits_{d|n} sum_{j=0}^{lfloor frac{kd}{n} floor}F(d,j)sumlimits_{i=1}^n[(i/d,n/d)==1]\ ans&=frac{1}{n} sumlimits_{d|n} varphi(frac{n}{d})sum_{j=0}^{lfloor frac{kd}{n} floor}F(d,j)\ end{aligned} ]

由于需要(dge j),否则(F(d,j))没有意义,因此计算(sum_{j=0}^{lfloor frac{kd}{n} floor}F(d,j))的时间复杂度至多为(O(d))

(sumlimits_{d|n} d=sumlimits_{d|n}frac{n}{d}le sumlimits_{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
",mul(ans,inv(n)));
    }
}
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/15081019.html