• 校内集训20181003


    $T1$:

    现在给你$N+1$个数,其中有$N$个数是合法的,合法的定义是$A_i=x imes p_i$,其中$x$为固定合数,$p_i$为两两互异的质数。

    还有一个数是不合法的,不合法即要么不满足除$x$的商是一个质数,要么不整除$x$,现在请找出那个不合法的数。

    $Nleq10^5,xleq10^5,p_ileq1.5 imes10^6$

     

    $Solution$:

    如果所有合法的数都是形如一个大合数乘一个素数的,那我们直接从$A$里随便取三个数两两求$gcd$,出现两次及以上的不就是$x$了?

    既然这样,那我为什么一开始想了一堆$O(log^2)$的奇形怪状的方法强行耽误时间……

    (正北方的刘某同学写了表筛$LLE$(代码长度超限)了,堪称千古绝唱)

    $Code$:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    #define MAXN 100005
    #define MAXM 1500005
    #define INF 0x7fffffff
    #define ll long long
    
    ll A[MAXN],p[MAXM],isp[MAXM],cnt;
    inline ll read(){
        ll x=0,f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar())
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar())
            x=x*10+c-'0';
        return x*f;
    }
    
    
    inline void init(ll x){
        memset(isp,-1,sizeof(isp));
        for(ll i=2;i<=x;i++){
            //cout<<i<<endl;
            if(isp[i]==-1) p[++cnt]=i,isp[i]=1;
            for(ll j=1;j<=cnt;j++){
                if(i*p[j]>x) break;
                isp[i*p[j]]=0;
                if(i%p[j]==0) break;
            }
        }
        return;    
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        init(MAXM-5);
        ll N=read(),num=0,maxm=0,x=-1;
        bool flag=0;
        for(ll i=1;i<=N+1;i++) A[i]=read();
        for(ll k=1;k<=MAXN;k++){
            bool tp1=0;ll tp2=0;
            for(ll i=1;i<=N+1;i++){
                if(A[i]/k>MAXM-5) {if(tp1) break;else tp1=1;}  
                else if(!isp[A[i]/k] || A[i]==k || A[i]%k!=0) {if(tp1) break;else tp1=1;}  
                else tp2++;if(tp2==3) {x=k;flag=1;break;}
            }
            if(flag) break;
        }
        for(ll i=1;i<=N+1;i++)
            if(A[i]/x>MAXM-5 || !isp[A[i]/x] || A[i]%x!=0)
                {printf("%lld
    ",A[i]);break;}
        return 0;
    }

    $T2$:

    给你$N$块密度均匀且宽,高相等的积木坐标$l_i,r_i$,现在需要你把这$N$块积木按序分成任意座积木塔,

    你需要保证把所有积木塔从低到高搭起来时不会出现不稳定结构,问含积木块数最多的积木塔最少可以含多少块积木。

    稳定的定义:

    若一个积木塔有$N$层,当且仅当对于$∀iin[1,N)$,从上至下数,前$i$块积木的重心落在第$i+1$块积木的覆盖范围内,
    则稳定,否则不稳定。前$i$块积木的重心为前$i$块积木的几何中心,以质量为权重的带权平均位置。

    $Nleq10^3,l_i,r_ileq10^4$

    $Solution$:

    这题最难的点在于知道带权平均数的计算方式为

    $$ave=frac {sum_{i=1}^{n}   {w_i imes p_i}} {sum_{i=1}^{n}   {w_i}}$$

    然后就没难点了……设$dp(i)$表示从下到上处理到第$i$块积木的答案,

    预处理${A_i...A_j}$是否稳定后枚举最后一座塔的形态即可实现$O(N^2)$转移。

    $Code$:(手懒贴了wls巨佬的)

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    inline ll read() {
        ll x=0,f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
        
    }
    int n;
    double L[1005],R[1005];
    double g[1005][1005],sz[1005][1005];
    bool vis[1005][1005];
    int dp[1005];
    int main() {
        n=read();
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) vis[i][j]=1;
        for(int i=1;i<=n;i++) {
            scanf("%lf%lf",&L[i],&R[i]);
            g[i][i]=(R[i]+L[i])/2;sz[i][i]=(R[i]-L[i]);
            vis[i][i]=1;
        }
        for(int i=1;i<=n;i++) {
            for(int j=i+1;j<=n;j++) {
                sz[i][j]=sz[i][j-1]+R[j]-L[j];
                g[i][j]=(g[i][j-1]*sz[i][j-1]+g[j][j]*sz[j][j])/sz[i][j];
                vis[i][j]=vis[i][j-1];
                if(!(g[i][j-1]>=L[j]&&g[i][j-1]<=R[j])) vis[i][j]=0;
            }
        }
        memset(dp,27,sizeof(dp));
        dp[n+1]=0;
        for(int i=n;i>=1;i--) {
            for(int j=i;j<=n;j++) {
                if(!vis[i][j]) break;
                if(!vis[i][n]) continue;
                if(j==n||(g[i][j]>=L[j+1]&&g[i][j]<=R[j+1])) dp[i]=min(dp[i],max(dp[j+1],j-i+1));
            }
        }
        printf("%d
    ",dp[1]);
    }

    $T3$:

    两列火车第一列$na$节车厢,第二列$nb$节车厢,每个车厢里有若干个${1...N}$之间的整数,每个整数在两列车里出现且仅出现一次。

    现在你需要按某种顺序排列车厢,然后把第一列车的车厢中的数按顺序取出扔到栈1,第二列扔到栈2。

    再对栈1栈2进行$k$次操作,每次操作弹出一个栈顶放到另一个栈顶。$k$次操作后${1...N}$每个数都要在栈1顶出现过一次。

    问如何排列车厢使得$k$最小。

    $Nleq10^5,na,nbleq20$

    $Solution$:

    看了lv神的题解还是只会写暴力啊……

    暴力枚举车厢的排列顺序然后计算每种排列顺序的答案(这句话极其难以实现)后取$min$。

    正解大概是预处理出同一列车内车厢间连线数,车厢内连线距离,车厢到对侧列车连线数后状压$DP$。

    $Code$:(同上std)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define MAXN 100010
    #define MAXH 20
    using namespace std;
    const int Size=1<<16;
    char buffer[Size],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,Size,stdin);
            tail=(head=buffer)+l;
        }
        if(head==tail) return -1;
        return *head++;
    }
    inline int read()
    {
        int x=0,t=1,c;
        while(!isdigit(c=Getchar()))if(c=='-')t=-1;
        while(isdigit(c))x=x*10+c-'0',c=Getchar();
        return x*t;
    }
    int N,n[2];
    int k[2][MAXH],s[2];
    int side[MAXN],block[MAXN],pos[MAXN];
    long long opposite[2][MAXH];
    long long link[2][MAXH][MAXH];
    long long inside[2][MAXH];
    long long cross[2][MAXH][MAXH];
    long long f[2][1<<MAXH];
    long long cf[2][1<<MAXH];
    long long csum[2][MAXN];
    long long lsum[MAXH][1<<MAXH];
    int LOG[1<<MAXH];
    int base;
    int rev(int x){return (~x)&base;}
    int lowbit(int x){return x&-x;}
    void GetLinkSum(int side,int j,int x)
    {
        int revx=rev(x),key=lowbit(revx),from=revx-key;
        lsum[j][x]=lsum[j][rev(from)]+link[side][j][LOG[key]];
    }
    long long TakeMin(long long &a,long long b)
    {
        return a=min(a,b);
    }
    void Update(int side,int state)
    {
        long long Remain=0;
        for(int i=0;i<n[side];i++)
        {
            bool hasi=state&(1<<i);
            if(!hasi)Remain+=k[side][i];
        }
        for(int i=0;i<n[side];i++)
        {
            int newstate=state|(1<<i);
            long long Raise=0,Cro;
            if(!(state&(1<<i)))
            {
                Raise=inside[side][i]+opposite[side][i]*(Remain-k[side][i]);
                Raise+=lsum[i][newstate];
                Cro=(cf[side][state]+cf[side][newstate]-csum[side][i])/2;
                Raise+=Cro*k[side][i];
                TakeMin(f[side][newstate],f[side][state]+Raise);
            }
        }
    }
    void BuildTransdata(int side,int x)
    {
        int key=lowbit(x),from_state=x-key;
        long long ret=cf[side][from_state];
        for(int i=0;i<n[side];i++)
        {
            if((1<<i)&key)
            {
                key=i;
                break;
            }
        }
        for(int i=0;i<n[side];i++)
        {
            if(i==key)continue;
            if((1<<i)&x)
            {
                ret-=cross[side][i][key];
            }
            else
            {
                ret+=cross[side][i][key];
            }
        }
        cf[side][x]=ret;
    }
    int main()
    {
        N=read();n[0]=read();n[1]=read();
        for(int i=0;i<n[0];i++)
        {
            k[0][i]=read();
            s[0]+=k[0][i];
            for(int j=1;j<=k[0][i];j++)
            {
                int node=read();
                side[node]=0;
                block[node]=i;
                pos[node]=j;
            }
        }
        for(int i=0;i<n[1];i++)
        {
            k[1][i]=read();
            s[1]+=k[1][i];
            for(int j=1;j<=k[1][i];j++)
            {
                int node=read();
                side[node]=1;
                block[node]=i;
                pos[node]=j;
            }
        }
        opposite[side[1]][block[1]]++;
        inside[side[1]][block[1]]+=k[side[1]][block[1]]-pos[1]+side[1];
        for(int x=1;x<N;x++)
        {
            int y=x+1;
            if(side[x]!=side[y])
            {
                opposite[side[x]][block[x]]++;
                opposite[side[y]][block[y]]++;
                inside[side[x]][block[x]]+=k[side[x]][block[x]]-pos[x]+side[x];
                inside[side[y]][block[y]]+=k[side[y]][block[y]]-pos[y]+side[y];
            }
            else
            {
                if(block[x]==block[y])
                {
                    inside[side[x]][block[x]]+=abs(pos[x]-pos[y]);
                }
                else
                {
                    cross[side[x]][block[x]][block[y]]++;
                    cross[side[x]][block[y]][block[x]]++;
                    link[side[x]][block[x]][block[y]]+=k[side[x]][block[x]]-pos[x]+pos[y];
                    link[side[x]][block[y]][block[x]]+=k[side[x]][block[y]]-pos[y]+pos[x];
                }
            }
        }
        cf[0][0]=0;
        cf[1][0]=0;
        for(int i=1;i<(1<<n[0]);i++)BuildTransdata(0,i);
        for(int i=1;i<(1<<n[1]);i++)BuildTransdata(1,i);
        for(int i=0;i<n[0];i++)
            for(int j=0;j<n[0];j++)
                csum[0][i]+=cross[0][i][j];
        for(int i=0;i<n[1];i++)
            for(int j=0;j<n[1];j++)
                csum[1][i]+=cross[1][i][j];
        memset(f,127,sizeof f);
        f[0][0]=f[1][0]=0;
        for(int i=2;i<(1<<n[0]);i++)LOG[i]=LOG[i>>1]+1;
        base=(1<<n[0])-1;
        for(int i=0;i<n[0];i++)lsum[i][base]=0;
        for(int i=0;i<n[0];i++)
            for(int j=base-1;j>=0;j--)
                GetLinkSum(0,i,j);
        for(int i=0;i<(1<<n[0])-1;i++)
            Update(0,i);
        for(int i=2;i<(1<<n[1]);i++)LOG[i]=LOG[i>>1]+1;
        base=(1<<n[1])-1;
        for(int i=0;i<n[1];i++)lsum[i][base]=0;
        for(int i=0;i<n[1];i++)
            for(int j=base-1;j>=0;j--)
                GetLinkSum(1,i,j);
        for(int i=0;i<(1<<n[1])-1;i++)
            Update(1,i);
        printf("%lld
    ",f[0][(1<<n[0])-1]+f[1][(1<<n[1])-1]);
    }
  • 相关阅读:
    【販売管理】「クレジットメモとデビットメモ」
    COALESCE [NULL でない最初の式を返す」
    【EXCEL】CONCAT(複数の文字列の連結)
    文字列内の検索 FIND
    テーブルコントロールTable Controls: スクロールを伴う場合の例
    SAP ABAP プログラム 選択画面定義 基本命令
    【転載】表示レイアウト実装方法
    php在linux中执行外部命令
    openldap+php-ldap操作
    MAC Ruby版本需要升级至2.2.2以上
  • 原文地址:https://www.cnblogs.com/YSFAC/p/9757076.html
Copyright © 2020-2023  润新知