11.9贺题大赛

四道题三道原题,牛的。

T1

同NOIP2018 旅行。

暴力枚举每条边即可。

T2

同NOIP2017 天天爱跑步。

树上差分,考试的时候真,没时间写。

T3

同NOIP2016 愤怒的小鸟

考虑一个只有两个未知量的二次函数能被两个点确定,我们暴力枚举每个点,特判\(x_i=x_j\)\(a\geq0\)的情况。

然后就变成了一个显然的区间\(DP\).

#include <bits/stdc++.h>
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<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}
inline void file(){
	freopen("terrorist.in","r",stdin);
	freopen("terrorist.out","w",stdout);
}
#define N 18
#define M (1<<N)
const double eps=1e-6;
int f[M];
int g[N][N];
int lb[M];
struct node{
	double x,y;
}q[N];
inline int cmp(double a,double b){
	if(fabs(a-b)<=eps)return 0;
	return a<b?-1:1;
}
inline void work(){
	int n=read(),m=read();
	for(int i=0;i<n;i++){
		scanf("%lf %lf",&q[i].x,&q[i].y); 
	}
	for(int i=0;i<(1<<n)-1;i++){
		for(int j=0;j<n;j++){
			if(!(i>>j&1)){lb[i]=j;break;}
		}
	}
	memset(g,0,sizeof(g));
	for(int i=0;i<n;i++){
		g[i][i]=(1<<i);
		for(int j=0;j<n;j++){
			if(!cmp(q[i].x,q[j].x))continue;
			double xx1=q[i].x,yy1=q[i].y,xx2=q[j].x,yy2=q[j].y;
			double b=(yy1*xx2*xx2-yy2*xx1*xx1)/(xx2*xx2*xx1-xx2*xx1*xx1);
			double a=(yy1-b*xx1)/(xx1*xx1);
			//cout<<i<<' '<<j<<' '<<a<<' '<<b<<endl;
			if(a>=0)continue;
			int fl=0;
			for(int k=0;k<n;k++){
				double dx=q[k].x,dy=q[k].y;
				if(!cmp(dy,a*dx*dx+b*dx))fl+=(1<<k);
			}
			g[i][j]=fl;
		}
	}
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	for(int i=0;i<(1<<n)-1;i++){
		for(int j=0;j<n;j++)
		f[i|g[lb[i]][j]]=min(f[i|g[lb[i]][j]],f[i]+1);
	}
	printf("%d\n",f[(1<<n)-1]);
}
int main(void){
	file();
	int T=read();
	while(T--)work();
	
}
/*
1
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00
*/ 

T4

\[\prod_{i_1=1}^n\prod_{i_2=1}^n...\prod_{i_k=1}^n\frac{i_1i_2i_3...i_k}{\gcd(i_1,i_2,...,i_k)} \]

\(T\)组数据。

\(n\leq 3\times 10^5,k\leq 10^{18},T\leq 2\times 10^3\)

sol

考虑把分子分母拆开来求(反正我不会合起来QAQ)

对于分子。

\[\prod_{i_1=1}^n\prod_{i_2=1}^n...\prod_{i_k=1}^ni_1i_2...i_k=(n!)^{kn^{k-1}} \]

主要是考虑分母

\[\prod_{i_1=1}^n\prod_{i_2=1}^n...\prod_{i_k=1}^n\gcd(i_1,i_2,...i_k)=\prod_{d=1}^nd^{\sum_{i_1=1}^n \sum_{i_2=1}^{n}...\sum_{i_k=1}^n[\gcd(i_1,i_2...i_k)=d]} \]

我们单独考虑指数,这就是一个很naive的莫反,最后得到

\[\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)(\lfloor \frac{n}{dp}\rfloor)^k \]

如果直接求上式,考虑在整除分块下整除分块,最终复杂度为\(O(n^{\frac{3}{4}}logk)\)会被卡,所以考虑预处理\((\lfloor \frac{n}{dp}\rfloor)^k\),有一个性质,即\((\lfloor \frac{n}{a}\rfloor)^k\)在只会有\(\sqrt n\)个取值。我们通过一次整除分块预处理出\((\lfloor \frac{n}{dp}\rfloor)^k\)的值,把它丢进一个哈希表,每次询问时\(O(1)\)取出即可。最终的\(logn\)\(\sqrt n\)做加法,总复杂度为\(O(Tn^{\frac{3}{4}})\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
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<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}
inline void file(){
	freopen("lcm.in","r",stdin);
	freopen("lcm.out","w",stdout);
}
const int mod=998244353;
inline int ksm(int a,int b,int mod){
	int res=1ll;
	while(b){
		if(b&1)res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res%mod;
}
#define N 1000005
#define S 1005
int s,n,k;
int mu[N+5],fac[N+5],invfac[N+5];
bool vis[N+5];
int p[N],num;
int idiv[S],adiv[S],cnt;
int hsh[(S<<1)+5];
inline int &id(int x){
	return x<=s?idiv[x]:adiv[n/x];
}
inline void pre(){
	mu[1]=fac[0]=fac[1]=1;
	for(int i=2;i<=N;i++){
		fac[i]=fac[i-1]*i%mod;
		if(!vis[i]){
			p[++num]=i;
			mu[i]=mod-2;
		}
		for(int j=1;j<=num&&p[j]*i<=N;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0)break;
			mu[i*p[j]]=(mod-1-mu[i])%(mod-1);
		}
		mu[i]=(mu[i]+mu[i-1])%(mod-1);
	}
	invfac[N]=ksm(fac[N],mod-2,mod);
	for(int i=N;i;i--){
		invfac[i-1]=invfac[i]*i%mod;
	}
}
inline void work(){
	n=read(),k=read();
	int fz=ksm(fac[n],(k%(mod-1))*ksm(n,k-1,mod-1)%(mod-1),mod);
	 //cout<<fz<<endl;
	s=sqrt(n);
	int fm=1ll;
	cnt=0;
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		hsh[id(n/l)=++cnt]=ksm(n/l,k,mod-1);
	}
	
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		int lsw=0,at=n/l;
		for(int L=1,R;L<=at;L=R+1){
			R=at/(at/L);
			lsw=(lsw+hsh[id(at/L)]*(mu[R]-mu[L-1]+mod-1))%(mod-1);	
		}
		fm=fm*ksm(fac[r]*invfac[l-1]%mod,lsw,mod)%mod;
	}
	printf("%lld\n",fz*ksm(fm,mod-2,mod)%mod);
}
signed main(void){
	file();
	pre();
	int T=read();
	while(T--)work();
	return 0;
}
posted @ 2021-11-09 16:28  xxbzzyw  阅读(50)  评论(0编辑  收藏  举报