校内集训20181003

$T1$:

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

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

$N\leq10^5,x\leq10^5,p_i\leq1.5\times10^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\n",A[i]);break;}
    return 0;
}

 

 

$T2$:

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

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

稳定的定义:

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

$N\leq10^3,l_i,r_i\leq10^4$

 

$Solution$:

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

$$ave=\frac {\sum_{i=1}^{n}   {w_i \times 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\n",dp[1]);
}

 

 

$T3$:

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

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

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

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

$N\leq10^5,na,nb\leq20$

 

$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\n",f[0][(1<<n[0])-1]+f[1][(1<<n[1])-1]);
}

 

posted @ 2018-10-09 23:09  Fugtemypt  阅读(179)  评论(0编辑  收藏  举报