9.1集训小结TAT

2 篇文章 0 订阅
2 篇文章 0 订阅

T1:

是一道简单的实数二分,不多说,注意精度问题!!

#include<cstdio>
#include<cmath>
 
using namespace std;
 
double emo=0.000000000001;//精度
double L,R;
 
inline double f(double x)
{
    return (double)exp(x*log(2))+exp(x*log(3))-exp(x*log(4))//等于2的x次幂+3的x次幂-4的x次幂;
}
 
int main(void)
{
    scanf("%lf%lf",&L,&R);
    while(R-L>emo){
        double mid=(L+R)/2.0;
        if(f((double)mid)<=0)R=mid;
        else L=mid;
    }
    printf("%.10lf",L);
}

T2:

 

乍眼一看是一道写过的状压DP,其实仔细分析一下便可以知道,它的棋面只有2格宽,进一步分析可以得知,上下的状态必定是一样的,所以只用看一行。问题转化为:一条棋面,用1*1的方块或者1*2的方块填满。那不就是跳楼梯吗?

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

普通DP直接过

#include<cstdio>
 
using namespace std;
 
int n;
long long f[32];    
 
int main(void)
{
    scanf("%d",&n);
    f[1]=1ll;f[0]=1ll;
    for(int i=2;i<=n;i++){
        f[i]=f[i-1]+f[i-2];
    }
    printf("%lld",f[n]);
}
//十六行结束战斗

T3:

 

第一眼确实看出来了是一道贪心题,但是排序的方案出了问题,并不是按照y为第一关键字,c为第二关键字,而应该是那c+y的和进行排序

证明:
    比较max(sum-bi,sum+ai-bj)和max (sum-bj, sum+aj-bi)的大小。明显,sum-bi<sum+aj-bi,sum-bj<sum+ai-bj。所以,只需要比较sum+ai-bj和sum+aj-bi的大小。假定sum+ai-bj<sum+aj-bi,那么,我们可以得到ai+bi<aj+bj。

    从上面的分析可以看出,如果i比j放在前面更优,就一定有ai+bi<aj+bj。那么,只需要按照a+b为关键字升序排序,即可得到最优排列,计算出最大的伤害值,即为答案。

#include<cstdio>
#include<algorithm>
 
using namespace std;
 
struct karsa{
    int y,c;
    int val;
}a[50005];
 
int n;
int sum,maxx=-0x7fffffff;
 
inline bool tmp(karsa x,karsa y){return x.y==y.y?x.c<y.c:x.y<y.y;}
 
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].y,&a[i].c);
    }
    sort(a+1,a+1+n,tmp);
    sum=a[1].y;
    for(int i=2;i<=n;i++){
        a[i].val=sum-a[i].c;
        sum+=a[i].y;
    }
    for(int i=1;i<=n;i++)maxx=max(maxx,a[i].val);
    printf("%d",maxx);
}

T4:

其实就是一道模拟题,但是本人太蠢了,没有读懂约瑟夫游戏要干什么,所以就没做TAT

不难发现,将数据用对列存储起来就可以非常方便的进行修改 

核心:

 q.push(q.front());    q.pop();    q.pop();

这一行就巧妙的实现了隔一个踢出一个的操作

#include<cstdio>
#include<queue>
 
using namespace std;
 
int n,win,ans;
queue<int> q;
 
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)q.push(i);
    while(1){
        while(q.size()>1){
            q.push(q.front());
            q.pop();
            q.pop();
        }
        if(win==q.front()){
            ans=win;
            break;
        }
        win=q.front();
        q.pop();
        for(int i=1;i<=win;i++)q.push(i);
    }
    printf("%d",ans+n);
}

T5:

 01背包,板子都不带改的,铭记复习

#include<cstdio>
#include<algorithm>
 
using namespace std;
 
struct tk{
    int value;
    int rank;
}a[30];
 
int n,m;
int f[300000];
int ans=0;
 
int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d",&a[i].value,&a[i].rank);
    for(int i=1;i<=m;i++){
        for(int j=n;j>=a[i].value;j--){
            f[j]=max(f[j],f[j-a[i].value]+a[i].value*a[i].rank);
        }
    }
    for(int i=n;i>=0;i--)ans=max(ans,f[i]);
    printf("%d\n",ans);
}

T6:

刚开始以为是道铁铁的DP题,本来想先写暴力DFS然后写个“NB”的DP来对拍的。可是没想到正解就是DFS,可自己DFS忘记了特判输出-1的情况,痛失此题QAQ

#include<cstdio>
#include<algorithm>
 
using namespace std;
 
int N,A,B;
int mov[210];
int INF=0x7fffff;
int ans=0x7fffff;
bool vis[210];
 
inline void dfs(int now,int fath,int dep)
{
    if(now>N || now<1 || vis[now]==1)return ;
    //d[now]=d[fath]+1;
    if(ans<dep)return ;
    vis[now]=1;
    if(now==B){
        ans=min(ans,dep);
        return ;
    }
    dfs(now+mov[now],now,dep+1);
    dfs(now-mov[now],now,dep+1);
    vis[now]=0;
}
 
int main(void)
{
    scanf("%d%d%d",&N,&A,&B);
    for(int i=1;i<=N;i++){scanf("%d",&mov[i]);}
    dfs(A,0,0);
    printf("%d",ans==INF?-1:ans);
}

T7:

不多说了,并查集做过的原题,精髓是将敌人的编号设为x+n,朋友就是x本身,最后计算头儿的个数来计算团伙个数

#include<cstdio>
 
using namespace std;
 
int n,m;
int fa[3010];
int size[3010];
int ans=0;
 
inline int find(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n*2;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int p,x,y;
        scanf("%d%d%d",&p,&x,&y);
        if(p==0){
            fa[find(x)]=find(y);
        }
        else{
            fa[find(x+n)]=find(y);//精髓
            fa[find(y+n)]=find(x);
        }
    }
    for(int i=1;i<=n;i++){
        if(fa[i]==i)ans++;
    }
    printf("%d",ans);
}

T8:

模拟,被整吐了

WA码:

#include<cstdio>
#include<cstring>
#include<string>
 
using namespace std;
 
struct node {
    int d;
    int x,y;
    bool flag;
} a,b;
 
int T,n;
int mov[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool f=0;
bool m1[1010][1010];
bool m2[1010][1010];
 
int main(void) {
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        scanf("%d%d%d",&a.x,&a.y,&a.d);
        scanf("%d%d%d",&b.x,&b.y,&b.d);
        a.x++;a.y++;a.flag=0;
        b.x++;b.y++;b.flag=0;
         
        memset(m1,0,sizeof(m1));
        memset(m2,0,sizeof(m2));
        f=0;
         
        for(int i=0;i<=n+1;i++)m1[i][0]=m2[i][0]=1;
        for(int i=0;i<=n+1;i++)m1[i][n+1]=m2[i][n+1]=1;
         
        for(int i=0;i<=n+1;i++)m1[0][i]=m2[0][i]=1;
        for(int i=0;i<=n+1;i++)m1[n+1][i]=m2[n+1][i]=1;
         
        while(a.flag!=1 || b.flag!=1) {
        m1[a.x][a.y]=1;m2[b.x][b.y]=1;
            if(a.x==b.x && a.y==b.y) {
                f=1;
                break;
            }
             
            int pa=0,pb=0;
             
            if(m1[a.x][a.y+1]==1 && a.d==1)
                a.d=2,pa++;
            if(m1[a.x-1][a.y]==1 && a.d==2)
                a.d=3,pa++;
            if(m1[a.x][a.y-1]==1 && a.d==3)
                a.d=0,pa++;
            if(m1[a.x+1][a.y]==1 && a.d==0)
                a.d=1,pa++;
             
            if(m1[a.x][a.y+1]==1 && m1[a.x-1][a.y]==1 && m1[a.x][a.y-1]==1 && m1[a.x+1][a.y]==1)a.flag=1;
             
            if(m2[b.x+1][b.y]==1 && b.d==0)
                b.d=3,pb++;
            if(m2[b.x][b.y-1]==1 && b.d==3)
                b.d=2,pb++;
            if(m2[b.x-1][b.y]==1 && b.d==2)
                b.d=1,pb++;
            if(m2[b.x][b.y+1]==1 && b.d==1)
                b.d=0,pb++;
                 
            if(m2[b.x][b.y+1]==1 && m2[b.x-1][b.y]==1 && m2[b.x][b.y-1]==1 && m2[b.x+1][b.y]==1)b.flag=1;
                 
            if(a.d==1 && a.flag==0) {
                a.y+=1;
//              if(a.y==n) 
//                  a.d=2;
                 
            } else {
                if(a.d==2 && a.flag==0) {
                    a.x-=1;
//                  if(a.x==1)
//                      a.d=3;
                     
                } else {
                    if(a.d==3 && a.flag==0) {
                        a.y-=1;
//                      if(a.y==1)
//                          a.d=0;
                         
                    } else {
                        if(a.d==0 && a.flag==0) {
                            a.x+=1;
//                          if(a.x==n)
//                              a.d=1;
                             
                        }
                    }
                }
            }
            if(b.d==1 && b.flag==0) {
                b.y+=1;
//              if(b.y==n) 
//                  b.d=0;
                 
            } else {
                if(b.d==2 && b.flag==0) {
                    b.x-=1;
//                  if(b.x==1)
//                      b.d=1;
                 
                } else {
                    if(b.d==3 && b.flag==0) {
                        b.y-=1;
//                      if(b.y==1)
//                          b.d=2;
                         
                    } else {
                        if(b.d==0 && b.flag==0) {
                            b.x+=1;
//                          if(b.x==n)
//                              b.d=3;
                        }
                    }
                }
            }
        }
        if(f==1) {
            printf("%d %d\n",b.x-1,b.y-1);
        } else {
            printf("-1\n");
        }
    }
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值