10.6清北刷题记

10.6 Morning


居然拿到了rk5,还get到了qbxt的小恩小惠

今天真是欧啊


Problem A.hi

【题目描述】

LYK最近学了最长子序列。发现这玩意儿太简单了。

它发明了属于自己的子序列。

即:给定n个数ai,选择其中若干个数按顺序形成子序列,要求满足这个子序列中任意相邻两个数做位运算与运算后都不等于0。(例如2&4=0,1&3=1)

LYK想知道这个子序列最长有多长。

【输入描述】

第一行一个数n。

接下来一行n个数表示ai。

【输出描述】

一个数表示这个子序列最长多长。

【输入输出样例】

【input】

3

1 2 3

【output】

2

【数据范围】

对于20%的数据n<=10。

对于60%的数据n<=1000。

对于100%的数据1<=n<=100000, 0<=ai<=10^9。


zhw蜜汁题解:f[x] 表示二进制意义下第x位为1的数结尾的最长子序列是多少

dp[i] 以a[i]结尾的最长子序列是多少

枚举所有x,若a[i]&(1<<x),就可以从f[x]+1转移得到dp[i]。最终用dp[i]去更新f。


【代码实现】

博主闲的没事在考场上写的20分暴力

/*
    Coded by Apojacsleam
*/
#include<cstdio>
#include<algorithm>
#define N 100001
int n,a[N],p,q,ans;
int main()
{
    freopen("hi.in","r",stdin);
    freopen("bl.out","w",stdout);
    scanf("%d",&n);
    for(register int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(register int i=1;i<=(1<<n)-1;i++)
    {
        p=(1<<29)-1;q=0;
        for(register int j=1;j<=n;j++)
          if((i&(1<<(j-1)))&&(p&a[j]))
          {
            p=a[j];
            q++;
          }
        ans=std::max(ans,q);
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

博主没事在考场上写的60分暴力

/*
    Coded by Apojacsleam
*/
#include<cstdio>
#include<algorithm>
#define N 100001
int n,a[N],dp[N],ans;
int main()
{
    freopen("hi.in","r",stdin);
    freopen("hi.out","w",stdout);
    scanf("%d",&n);
    for(register int i=1;i<=n;i++) scanf("%d",&a[i]),dp[i]=1;
    for(register int i=1;i<=n;i++)
    {
        for(register int j=1;j<i;j++)
          if(a[i]&a[j]) dp[i]=std::max(dp[i],dp[j]+1);
        ans=std::max(ans,dp[i]);
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

博主在考场上闲的没事写的100分正解

/*
    Coded by Apojacsleam
*/
#include<cstdio>
#include<algorithm>
#define N 100001
int n,dp[N],ans,f[40];
long long a[N];
int main()
{
    freopen("hi.in","r",stdin);
    freopen("hi.out","w",stdout);
    scanf("%d",&n);
    for(register int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(register int i=1;i<=n;i++)
    {
        for(register long long j=0;j<=32;j++)
          if(a[i]&(1<<j)) dp[i]=std::max(dp[i],f[j]+1);
        for(register long long j=0;j<=32;j++)
          if(a[i]&(1<<j)) f[j]=std::max(f[j],dp[i]);
        ans=std::max(ans,dp[i]);
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

Problem B. haha

【题目描述】

LYK在一个K维空间中。

它有n条飞船,第i条飞船所在的位置是{s[i][1],s[i][2],...,s[i][K]}。

它想利用这n条飞船去摧毁水晶,这个水晶是一个中心点在{c1,c2,...,cK}且半径为r的范数球。

所谓半径为r的范数球是指:任意距离这个水晶中心点的曼哈顿距离(每维坐标差的绝对值的和)小于等于r的点,都处于这个水晶中。

你想用这些飞船攻击这个水晶,但是进攻的能量会随着距离衰减,因此对于每条飞船,你都需要找一个水晶的位置,使得离这条飞船的欧式距离(每维坐标差的平方和再开根)最短。

LYK保证这n条飞船都不在水晶所在的范数球中。

LYK想知道这n个最短的欧氏距离之和是多少。

【输入描述】

一行两个数n,K。表示有n条飞船,LYK在K维空间中。

接下来一行一个数r。

接下来一行K个数,表示这个水晶的中心点。

接下来n行,每行K个数,表示每条飞船所在的位置。

【输出描述】

一个数表示所有欧氏距离之和,答案保留3位小数。(四舍五入)

【输入输出样例】

【input】

2 2

1

0 0

1 1

1 3

【output】

2.943

【数据范围】

对于30%的数据K=1。

对于60%的数据K<=2。

对于100%的数据1<=K<=50,1<=n<=100, 1<=r<=1000,-1000<=s[x][y],c[x]<=1000。输入的数都是整数。


zhw蜜汁题解:

一开始把所有维度减去水晶中心的值。因此,我们可以默认水晶中心在{0,0,...}

对于一艘飞船,它的每个维度取它绝对值。

所有维度都是正整数,且要半径为r,中心在原点的范数球

把所有维度减去一个ai(不能成为负数),最终当所有维度之和=r时,就能攻击到范数球了。

最小化代价 = sqrt(sum{ai^2})

先将所有维度从小到大排序。

1 2 4 3 0 1 3
0 0.5 2.5

存在一个阈值x, 使得前x维,完全贴近中心, x+1~K维,每一维减去一个相同的值


【代码实现】

30分代码

#include<iostream> 
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
using namespace std;
int k,n;
double r;
double pos[1010][110];
int main()
{
    freopen("haha.in","r",stdin);
    freopen("haha.out","w",stdout);
    double ans=0;
    cin>>n>>k>>r;
    for(int i=0;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            cin>>pos[i][j];
        }
    }
    if(k==1)
    {
        double x1=pos[0][1]-r;
        double x2=pos[0][1]+r;
        for(int i=1;i<=n;i++)
        {
            double a1=x1-pos[i][1];
            double a2=x2-pos[i][1];
            if(a1<0) a1*=(-1);
            if(a2<0) a2*=(-1);
            if(a1<a2) ans+=a1;
                else ans+=a2;
        }
        cout<<setprecision(3)<<fixed<<ans;
    }
    return 0;
}

博主在考场上闲的没事写的60分代码

/*
    Coded by Apojacsleam
*/
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k,a,kk,r,yd[60],zb[110][60];
double nx,ans=0.0;
double calc_ou(double x1,double y1,double x2,double y2)
{
    return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
void baogank2()
{

    for(register int i=1;i<=n;++i)
    {
        zb[i][1]-=yd[1],zb[i][2]-=yd[2];
        if(zb[i][1]==0||zb[i][2]==0)
        {
            ans+=max(abs(zb[i][1]),abs(zb[i][2]))-r;
            continue;
        }
        if(zb[i][1]>0&&zb[i][2]>0)//1
        {
            a=1;
            kk=zb[i][2]-zb[i][1];
            nx=(double)(r-kk)/(double)(a+1);
            if(nx>=(double)0&&nx<=r)ans+=calc_ou(nx,nx+kk,zb[i][1],zb[i][2]);
            else ans+=min(calc_ou(0,r,zb[i][1],zb[i][2]),calc_ou(r,0,zb[i][1],zb[i][2]));
            continue;
        }
        if(zb[i][1]>0&&zb[i][2]<0)//4
        {
            a=-1;
            kk=zb[i][2]+zb[i][1];
            nx=(double)(-r-kk)/(double)(a-1);
            if(nx>=(double)0&&nx<=r)ans+=calc_ou(nx,-1*nx+kk,zb[i][1],zb[i][2]);
            else ans+=min(calc_ou(0,-1*r,zb[i][1],zb[i][2]),calc_ou(r,0,zb[i][1],zb[i][2]));
            continue;
        }
        if(zb[i][1]<0&&zb[i][2]>0)
        {
            a=-1;
            kk=zb[i][2]+zb[i][1];
            nx=(double)(r-kk)/(double)(a-1);
            if(nx<=(double)0&&nx>=-1.0*r)ans+=calc_ou(nx,-1*nx+kk,zb[i][1],zb[i][2]);
            else ans+=min(calc_ou(0,r,zb[i][1],zb[i][2]),calc_ou(-1*r,0,zb[i][1],zb[i][2]));
            continue;
        }
        if(zb[i][1]<0&&zb[i][2]<0)
        {
            a=1;
            kk=zb[i][2]-zb[i][1];
            nx=(double)(-r-kk)/(double)(a+1);
            if(nx<=(double)0&&nx>=-1.0*r)ans+=calc_ou(nx,nx+kk,zb[i][1],zb[i][2]);
            else ans+=min(calc_ou(0,-1*r,zb[i][1],zb[i][2]),calc_ou(-1*r,0,zb[i][1],zb[i][2]));
            continue;
        }
    }
}
int cx;
void baogank1()
{
    for(register int i=1;i<=n;++i)
    {
        zb[i][1]-=yd[1];
        cx=zb[i][1];
        if(cx>0)
        {
            ans+=cx-r;
            continue;
        }
        if(cx<0)
        {
            ans+=-r-cx;
            continue;
        }
    }
}
int main()
{
    freopen("haha.in","r",stdin);
    freopen("haha.out","w",stdout);
    scanf("%d%d%d",&n,&k,&r);
    for(register int i=1;i<=k;++i)scanf("%d",&yd[i]);
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=k;++j)
            scanf("%d",&zb[i][j]);
    if(k==2) baogank2();
    if(k==1) baogank1();
    printf("%.3lf",ans);
    return 0;
}

100分std

#include <bits/stdc++.h>
using namespace std;
int a[105],b[105],n,m,r,X,T,i,j,sum,d[105],h[105];
double c[105],ans,ANS;
struct node {int x,y;} t[105];
int cmp(node i,node j) {return i.x<j.x;}
double ANSS;
int main()
{
    freopen("haha.in","r",stdin);
    freopen("haha.out","w",stdout);
    T=1;
    while (T--)
    {
        scanf("%d%d",&n,&m);
        scanf("%d",&r);
        for (i=1; i<=m; i++) scanf("%d",&a[i]);
        while (n--)
        {
            for (i=1; i<=m; i++) {scanf("%d",&t[i].x);  t[i].x=abs(t[i].x-a[i]); t[i].y=i;}
            sort(t+1,t+m+1,cmp);
            for (i=1; i<=m; i++) b[i]=t[i].x;
            ANS=1000000000;
            for (i=0; i<m; i++)
            {
                ans=0;
                for (j=1; j<=i; j++) ans+=b[j]*b[j];
                sum=0;
                for (j=i+1; j<=m; j++) sum+=b[j];
                if ((double)(sum-r)/(m-i)>b[i+1]) continue;
                ans+=((double)(sum-r)*(sum-r)/(m-i));
                if (ans<ANS) {ANS=ans; X=i;}
            }
            ANSS+=sqrt(ANS);
        }
    }
    printf("%.3f\n",ANSS);
    return 0;
}

Problem C. math

LYK看到一个题:

计算(3+2√2)^n的整数部分对1000000007取模后的结果。 LYK不会做,来问你。你帮他做出来就能获得100分。

【输入格式】

一行一个数n。

【输出格式】

一个数答案。

【输入输出样例】

【input】

2

【output】

33

【数据范围】

对于20%的数据n<=4。

对于40%的数据n<=10。

对于60%的数据n<=100。

对于80%的数据n<=10^7。

对于100%的数据1<=n<=10^9。


zhw蜜汁题解

f[i]表示 (3+2sqrt2)^i + (3-2sqrt2)^i       ans = f[n] % 1e9+7  - 1

f[i]*f[j]

((3+2sqrt2)^i + (3-2sqrt2)^i)  *  ((3+2sqrt2)^j + (3-2sqrt2)^j)  (i>j)

(3+2sqrt2)^(i+j) + (3+2sqrt2)^(i-j) + (3-2sqrt2)^(i-j)+ (3-2sqrt2)^(i+j)

f[i]*f[j] = f[i+j] + f[i-j]
另j=1

f[i]*f[1] = f[i+1] + f[i-1]

f[i+1] = 6 * f[i] - f[i-1]   矩阵快速幂

① f[n] 尽可能把n分成均匀两份  n是偶数:  f[n]=f[n/2]*f[n/2]-2
                               n是奇数:  f[n]=f[n/2]*f[n/2+1]-6    T[n] = T[n/2] + T[n/4]

② f[n]是关于f[n-1]的递推式,打表打出f[100W],f[200W],...,f[10E]。  
求f[123456789] = f[123000000] 再往后推456789项。  O(100W)

【代码实现】

40分代码

#include<bits/stdc++.h> // 29 169 
using namespace std;
double ans = 1 ;
long long jishu ;
int main(){
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    int i ;
    cin >> i ;
    //for(int i = 1 ; i ; i++){
        for(int j = 1 ; j <= i ; j++){
            ans = ans * 5.82842712474619 ;
            jishu = (long long)ans ;
            jishu = jishu % 1000000007 ;
            if(j%10==0 ) ans = (double)jishu+1 ;
            //cout << ans << "     !" << endl ;
        }
        cout << jishu << endl ;
        ans = 1 ;
        jishu = 1 ;
    //}
} 

博主闲的没事在考场上打的40分的表(在这里卡了2h)

/*
    Coded by Apojacsleam
*/
#include<cstdio>
int n;
int a[11]={1,5,33,197,1153,6725,39201,228485,1331713,7761797,45239073};
int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
        scanf("%d",&n);
        if(n<=10) printf("%d\n",a[n]);
    return 0;
}

60分选手的代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int mo=1e9+7;
int k,n,c[5000005],san[10000005],ba[5000005],i,j,ans;
int pow(int x,int y){
    int a=x,res=1;
    while(y){
        if(y&1)res=(long long)res*(long long)a%mo;
        a=(long long)a*(long long)a%mo;
        y>>=1;
    }
    return res;
}
int main(){
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    cin>>n;
    ba[0]=1;c[0]=1;
    for(i=1;i<=n/2;i++){
        int res=(long long)c[i-1]*(long long)(n-(i*2-1)+1)%mo*(long long)pow(i*2-1,mo-2)%mo;
        c[i]=((long long)res*(long long)(n-i*2+1)%mo)*(long long)pow(i*2,mo-2)%mo;
        ba[i]=(long long)ba[i-1]*8%mo;
    }
    san[0]=1;
    for(i=1;i<=n;i++)san[i]=(long long)san[i-1]*(long long)3%mo;
    for(k=0;k<=n/2;k++){
        ans=((long long)ans+(long long)c[k]*(long long)ba[k]%mo*(long long)san[n-k*2]%mo)%mo;

    }
    ans=((long long)2*ans%mo-1+mo)%mo;
    cout<<ans<<endl;
    return 0;
}

80分选手的代码

#include <cstdio>

const int MOD = 1000000007, MAX_N = 1e7;

int n;
int a[2 * MAX_N + 100];

int main() {
    freopen("math.in", "r", stdin);
    freopen("math.out", "w", stdout);

    scanf("%d", &n);
    n *= 2;
    a[0] = 2; a[1] = 2;
    for (int i = 2; i <= n; ++i) a[i] = ((long long)a[i - 1] * 2 + a[i - 2]) % MOD;
//  for (int i = 0; i <= n; ++i) printf("%d ", a[i]);
    printf("%d", (a[n] - (n & 1 ? 0 : 1) + MOD) % MOD);

    return 0;
}

博主在考场上闲的没事写的100分代码

/*
    Coded by Apojacsleam
*/
#include<cstdio>
#define mod 1000000007
long long a,b,n;
struct NODE{
    int r,c;
    long long f[2][2];
};
NODE f1,f2,f3;
NODE cheng(NODE &a,NODE &b)
{
    NODE c;
    c.r=a.r;
    c.c=b.c;
    for(register int i=0;i<a.r;i++)
    for(register int j=0;j<b.c;j++)
    {
        c.f[i][j]=0;
        for(register int k=0;k<a.c;k++) c.f[i][j]+=a.f[i][k]*b.f[k][j];
        c.f[i][j]%=mod;
    }
    return c;
}
NODE ksm(int n)
{
    NODE res=f1,temp=f2;
    while(n)
    {
        if(n&1) res=cheng(res,temp);
        temp=cheng(temp,temp);
        n>>=1;
    }
    return res;
}
void doit()
{
    f1.r=f1.c=f2.c=f2.r=2;
    f1.f[0][0]=1;f1.f[0][1]=0;f1.f[1][0]=0;f1.f[1][1]=1;
    f2.f[0][0]=0;f2.f[0][1]=1;f2.f[1][0]=b-a*a;f2.f[1][1]=2*a;
    f3.r=2;f3.c=1;f3.f[0][0]=2*a;f3.f[1][0]=2*(a*a+b);
}
long long ans;
int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    a=3;b=8;
    scanf("%lld",&n);
    doit();
    if(n==1) ans=(2*a)%mod;
    else if(n==2) ans=(2*(a*a+b));
    else
    {
        NODE res=ksm(n-2);
        f3=cheng(res,f3);
        ans=(f3.f[1][0]+mod)%mod;
    }
    ans=(ans+mod-1)%mod;
    printf("%lld",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值