11.8多校联训
T1 漂亮厨师
Sol
分块维护数列求合法数个数,然后莫队/分段打表求组合数。
Code
#include<bits/stdc++.h>
using namespace std;
inline void File(){
freopen("cook.in","r",stdin);
freopen("cook.out","w",stdout);
}
const int N=1e5+5,mod=998244353;
inline int power(int a,int b){
int ret=1;
for(;b;b>>=1){
if(b&1)ret=1ll*ret*a%mod;
a=1ll*a*a%mod;
}
return ret;
}
int n,A[N],a[N];
namespace DivBlock{
int Len,pos[N],tag[N];
inline void Update(int x){
for(int i=(x-1)*Len+1;i<=min(x*Len,n);i++)A[i]=a[i];
sort(A+(x-1)*Len+1,A+min(n,x*Len)+1);
}
inline void Change(int l,int r,int x){
if(pos[l]==pos[r]){
for(int i=l;i<=r;i++)a[i]+=x;
Update(pos[l]);
return ;
}
for(int i=l;i<=pos[l]*Len;i++)a[i]+=x;
Update(pos[l]);
for(int i=pos[l]+1;i<=pos[r]-1;i++)tag[i]+=x;
for(int i=(pos[r]-1)*Len+1;i<=r;i++)a[i]+=x;
Update(pos[r]);
}
inline int Ask(int l,int r,int x){
int ret=0;
if(pos[l]==pos[r]){
for(int i=l;i<=r;i++)if(a[i]+tag[pos[l]]<=x)ret++;
return ret;
}
for(int i=l;i<=pos[l]*Len;i++)if(a[i]+tag[pos[l]]<=x)ret++;
for(int i=pos[l]+1;i<=pos[r]-1;i++)ret+=upper_bound(A+(i-1)*Len+1,A+i*Len+1,x-tag[i])-A-(i-1)*Len-1;
for(int i=(pos[r]-1)*Len+1;i<=r;i++)if(a[i]+tag[pos[r]]<=x)ret++;
return ret;
}
inline void Start(){
Len=sqrt(n);
for(int i=1;i<=n;i++)pos[i]=(i-1)/Len+1;
for(int i=1;i<=Len+1;i++)sort(A+(i-1)*Len+1,A+min(n,i*Len)+1);
}
}
namespace Main{
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
int Len,fac[N],inv[N];
int C(int nn,int m){
if(!m||nn==m)return 1;
if(m>nn)return 0;
return 1ll*fac[nn]*inv[m]%mod*inv[nn-m]%mod;
}
int m,maxn,ans[N],tot;
inline int Calc(int x){return (x-1)/Len+1;}
struct Que{
int x,y,id;
inline bool operator <(const Que X)const{
if(Calc(y)==Calc(X.y))return x<X.x;
return Calc(y)<Calc(X.y);
}
}q[N];
inline void Init(){
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv[n]=power(fac[n],mod-2);
for(int i=n-1;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
inline void Solve(){
n=read(),m=read();
for(int i=1;i<=n;i++)A[i]=a[i]=read();
DivBlock::Start();
for(int i=1;i<=m;i++){
int op=read(),l=read(),r=read();
if(op==1){
int x=read();
DivBlock::Change(l,r,x);
}
else {
int y=read(),k=read();
q[++tot].x=DivBlock::Ask(l,r,y);q[tot].y=k,q[tot].id=tot;
maxn=max(maxn,q[tot].x);
}
}
Len=(int)sqrt(maxn);
sort(q+1,q+tot+1);
Init();
int ret=1,l=0,r=0;
for(int i=1;i<=tot;i++){
while(r<q[i].x){
ret=((2ll*ret-C(r,l))%mod+mod)%mod;
r++;
}
while(r>q[i].x){
r--;
ret=(1ll*(ret+C(r,l))%mod*inv[2])%mod;
}
while(l<q[i].y){
l++;
ret=(ret+C(r,l))%mod;
}
while(l>q[i].y){
ret=(ret-C(r,l)+mod)%mod;
l--;
}
ans[q[i].id]=ret;
}
for(int i=1;i<=tot;i++)printf("%d\n",ans[i]);
}
}
int main(){
File();
Main::Solve();
return 0;
}
T2 吃树
Sol
可以证明:对于一个k满足k|n,当且仅当n个点子树大小有n/k个是k的倍数,可以分成n/k块吃掉。
具体证明:显然对于一个块大小k只有唯一的分解方式。假设已知一个k能作为分解的块大小,那么肯定有一块是一个点的子树,不断把这样的点删去,显然最后能删空,一次删一块,一共删n/k次,所以有n/k个点子树大小是k的倍数。
假设对于一个k,有n/k个点子树大小是k的倍数却无法分解,那么必有一个点,它自身是k的两倍或更多倍,而子树中不含有是k的倍数的子节点。那对于剩下n-2*k个点不存在满足含有n/k-1个子树大小是k的倍数的点的情况,所以必然可以分解。
1000000范围内最多约数的数大约200个,2e8小常数带O2优化能过。
Code
#include<bits/stdc++.h>
using namespace std;
namespace io
{
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return f?x:-x;
}
inline void print(int x)
{
static int s[30],len;len=0;
if(x==0)putchar('0');
if(x<0)putchar('-'),x=-x;
while(x)s[++len]=x%10,x/=10;
for(int i=len;i;i--)putchar(s[i]+'0');
return;
}
}
using namespace io;
const int maxn=1000010;
struct edge
{
int to,next;
}e[maxn<<1];
int h[maxn],ei;
inline void add(int x,int y)
{
e[++ei]=(edge){y,h[x]};
h[x]=ei;return;
}
int n;
int son[maxn],fa[maxn],siz[maxn];
inline void dfs(int x,int f)
{
siz[x]=1;
for(int i=h[x];i;i=e[i].next)
{
int to=e[i].to;
if(to==f)continue;
fa[to]=x;dfs(to,x);
siz[x]+=siz[to];
}
return;
}
int main()
{
freopen("eat.in","r",stdin);
freopen("eat.out","w",stdout);
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
int sq=sqrt(n),ans=2;dfs(1,0);
for(int i=2;i<=sq;i++)
{
if(n%i==0)
{
int cnt=0;
for(int j=1;j<=n;j++)
{
if(siz[j]%i==0)cnt++;
}
if(cnt>=n/i)ans++;cnt=0;
if(i*i==n)continue;
for(int j=1;j<=n;j++)
{
if(siz[j]%(n/i)==0)cnt++;
}
if(cnt>=i)ans++;
}
}
print(ans);putchar('\n');
return 0;
}
T3 飞翔的胖鸟
Sol
不会求导就写的三分,结果因为精度问题挂成15分。
对原式求导得到
\[f'(\theta)=b-\frac{ahcos(\theta)}{sin^2\theta}
\]
显然函数在导函数为0的时候取到最小值。
设\(x=cos\ \theta\),那么可以化成方程
\[b-\frac{ah*x}{1-x^2}=0\\
b*x^2+ah*x-b=0\\
x=\frac{-ah±\sqrt{k^2+4*b^2}}{2*b}
\]
由于\(\theta ∈(0,\frac{\pi}{2}]\),所以\(x∈[0,1)\)
所以求根公式取正。
注意精度问题即可。
Code
//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#include<math.h>
using namespace std;
namespace io
{
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return f?x:-x;
}
inline void print(int x)
{
static int s[30],len;len=0;
if(x==0)putchar('0');
if(x<0)putchar('-'),x=-x;
while(x)s[++len]=x%10,x/=10;
for(int i=len;i;i--)putchar(s[i]+'0');
return;
}
}
using namespace io;
int a,h,b,A,H,B;
const double pai=3.141592653589;
const long long p=19260817;
double nh,na,nb;
void Read()
{
long long x=1ll*h*H,y=1ll*a*A,z=1ll*b*B;
h=(H^(y+z))%1000+1;
a=(A^(x+z))%1000+1;
b=(B^(x+y))%100000+1;
nh=h*a;nb=b;return;
}
double nowa;
inline double check(double the)
{
return nh/sin(the)+nb*the;
}
inline void getans()
{
double l=0.0001,r=pai/2;
double thel=2*l/3+r/3,ther=l/3+2*r/3;
while(r-l>0.00001)
{
thel=2*l/3+r/3,ther=l/3+2*r/3;
//cout<<"zxh ak ioi"<<endl;
// cout<<l<<" "<<r<<endl;
// cout<<thel<<" "<<ther<<endl;
if(check(thel)>check(ther))l=thel+0.00001;
else r=ther;
}
nowa=check(l);return;
}
long long gpc[2000010];
inline long long ksm(long long x,long long mi)
{
long long rst=1;
while(mi)
{
if(mi&1)rst=rst*x%p;
x=x*x%p;mi>>=1;
}
return rst;
}
int main()
{
freopen("fly.in","r",stdin);
freopen("fly.out","w",stdout);
int typ=read(),T=read();
if(typ)
{
long long ans=0;
h=read();a=read();b=read();H=read();A=read();B=read();
for(int i=1;i<=T;i++)
{
Read();
nowa=sqrt(nh*nh/4/nb/nb+1)-nh/2/nb;
nowa=check(acos(nowa));
gpc[i]=nowa*10000;
}
for(int i=T;i;i--)
{
ans=(ans+gpc[i])*11514ll%p;
}
print(ans);putchar('\n');
return 0;
}else
{
while(T--)
{
h=read();a=read();b=read();
nh=h*a;nb=b;
if(b==0)
{
printf("%.4lf\n",nh);
}
nowa=sqrt(nh*nh/4/nb/nb+1)-nh/2/nb;
nowa=check(acos(nowa));
printf("%.4lf\n",nowa);
}
return 0;
}
}