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;
    }
}

T4 我是傻逼

posted @ 2021-11-08 22:06  wwlvv  阅读(52)  评论(0)    收藏  举报