ACdream原创群赛(18)题解6题

在ACdream群赛中,体验到提升A题解题速度的重要性。文章分享了对多道题目如Triangle、KIDx's Pagination、Points In Cuboid等的解题思路和心得,涉及到排序、模拟、数学原理等技巧。通过正弦定理、余弦定理解决复杂问题,并强调特殊情况处理,如角a等于0的情况。还提到了输入优化对效率的影响,以及处理大量查询的策略。
摘要由CSDN通过智能技术生成

2014/9/6 Tonight,在ACdream上做题,发现自己的A题速度有待提高,没什么失误率,基本上做题顺序跟着AC数最多的题走,囧!

在triangle 那题,∠a =0这个情况wa 4次才想到!               -----孙权


A - KIDx's Pagination

思路:模拟论坛分页的功能,先处理左边,右边的情况对称处理即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define N 50
#define M 1002
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
#define FOR(i,a,n)  for(int i=(a);i<=(n);++i)

int n,cur,d;
string s;
string convert(int i)
{
    char buf[5];
    sprintf(buf, "%d", i);
    string b = buf;
    return b;
}
void  solvel()
{
    int i=cur-1,cnt=1;
    if(cur==1)
    {
       s="[<<]"+s;
    }
    else
    {
        while(i>=1&&cnt<=d)
        {
            s="("+convert(i)+")"+s;
            i--;
            cnt++;
        }
        if(i>=1)s="[...]"+s;
        s="(<<)"+s;
    }
}
void  solver()
{
    int i=cur+1,cnt=1;
    if(cur==n)
    {
       s=s+"[>>]";
    }
    else
    {
        while(i<=n&&cnt<=d)
        {
            s=s+"("+convert(i)+")";
            i++;
            cnt++;
        }
        if(i<=n)s=s+"[...]";
        s=s+"(>>)";
    }
}
int main()
{
    int cnt=1;
    while(~scanf("%d%d%d",&n,&cur,&d))
    {
        s="["+convert(cur)+"]";
        solvel();
        solver();
        printf("Case #%d: %s\n",cnt++,s.c_str());
    }
    return 0;
}

B - Points In Cuboid

C - Transformers' Mission

D - Heros and Swords

思路:先将power 和 weight 排序,对于每个人i,他能拿的武器数量就是weight[ ] <=power[i],weight的个数,乘起来就行了,如果发现某个人没有武器可拿,直接返回0 即可。

效率:O(n*log(n)+ O(n))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define N 50
#define M 100002
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
#define FOR(i,a,n)  for(int i=(a);i<=(n);++i)


LL mod=1000000007;
int n;
int w[M],power[M];
LL solve()
{
    int j=0,cnt=0;
    LL ans=1;
    for(int i=0;i<n;i++)
    {
        while(j<n&&power[i]>=w[j])
        {
            cnt++;
            j++;
        }
        if(cnt==0)return (LL)0;
        ans=ans*cnt;if(ans>=mod)ans%=mod;
        cnt--;
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&w[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&power[i]);
         sort(w,w+n);
         sort(power,power+n);
         printf("Case #%d: %lld\n",i,solve());
    }
    return 0;
}

E - Jump! Jump! Jump!

F - SuSu's Power

G - Integer in C++

思路:正数和负数分别处理,从表示范围小的开始比较即可,直接比较string,<= 是说明可以表示。

string s;
string base[3]={"-32768","-2147483648","-9223372036854775808"};
string base2[3]={"32767","2147483647","9223372036854775807"};
int l[3]={6,11,20};
int r[3]={5,10,19};
string ans[4]={"short","int","long long","It is too big!"};
int compare(string a,string b,int len)
{ // <= 返回1
    for(int i=0;i<len;i++)
        if(a[i]!=b[i])
        return a[i]<b[i];
    return 1;
}
int solve(string* base,int* a)
{
    int n=s.length();
    if(n<a[0])return 0;
    else if(n==a[0]){
        if(compare(s,base[0],n))return 0;
        else return 1;
    }else if(n<a[1])
    {
        return 1;
    }else if(n==a[1])
    {
        if(compare(s,base[1],n))return 1;
        else return 2;
    }
    else if(n<a[2])
    {
        return 2;
    }else if(n==a[2])
    {
        if(compare(s,base[2],n))return 2;
        else return 3;
    }else
    {
        return 3;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int ret;
    while(cin>>s)
    {
        if(s[0]=='-')ret=solve(base,l);
        else ret=solve(base2,r);
        cout<<ans[ret]<<endl;
    }
    return 0;
}

H - KIDx's Triangle

思路:求边长假设底边长度为L,根据正弦定理,求出相应的边,根据余弦定理求出角度的余弦,

注意:当角a==0时,结果为0(wa了3次) 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define N 50
#define M 1002
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
#define FOR(i,a,n)  for(int i=(a);i<=(n);++i)

double a,b,c,d,A,B,D,E;
double PI=acos(-1.0);
double hudu=180.0/PI;
int main()
{
    double l1,l2,l3,l4,l5;
    double l=1.0;
   // printf("%.3lf",(double)sin(1.5));
  // printf("aaaa=%.6lf\n",cos(20.0/hudu));
  // printf("aaaa=%.2lf\n",180/PI*acos(0.939693));
    while(~scanf("%lf%lf%lf%lf",&a,&b,&c,&d))
    {
        if(a==0){printf("0.00\n");continue;}
        A=(a+b)/hudu;
        B=(c+d)/hudu;
        D=(180.0-a-b-c)/hudu;
        E=(180.0-b-c-d)/hudu;
        a=a/hudu;
        b=b/hudu;
        c=c/hudu;
        d=d/hudu;

        l2=l*sin(B)/sin(E);
        l3=l*sin(c)/sin(D);
        l4=l*sin(A)/sin(D);
        l5=l*sin(b)/sin(E);

        double doublel1=l4*l4+l5*l5-2*l4*l5*cos(d);
        l1=sqrt(1.0*doublel1);

        double cosarp= (l1*l1+l2*l2-l3*l3)/(2*l1*l2);

        double ans=hudu*acos(cosarp);

      //  printf("--->%.3lf-->",cosarp);
        printf("%.2lf\n",ans);
    }
    return 0;
}

I - Integration of Polynomial

思路:GCD求最大公约数

int n;
int k[1002],e[1002];
int GCD(int a,int b)
{
    return b==0?a:GCD(b,a%b);
}
void solve()
{
    int flag=1;
    int a,b;
    for(int i=0; i<n; i++)
    {
        a=k[i];
        b=e[i]+1;
        int p;
        if(a<0)p=GCD(-a,b);
        else p=GCD(a,b);
        a/=p;
        b/=p;

        if(b==1)
        {
            if(flag){printf("%d",a);flag=0;}
            else printf(" %d",a);
        }
        else
        {
            if(flag){printf("%d/%d",a,b);flag=0;}
            else printf(" %d/%d",a,b);
        }
        printf(" %d",e[i]+1);
    }
    printf("\n");
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&k[i],&e[i]);
        }
        solve();
    }
    return 0;
}

J - Disappeared Block

题意:这是真是一道好题!题意:有n个高度分别为hi(0<hi<10^9) 的城市在一条水平线上,每隔一分钟海水会淹没一层,t =0,海水高度为0,多次询问,问你k 分钟后,有多少个连通块(城市连在一起算一个)?

思路:逆向思维,终有一天,海水会淹没所有城市(有点像诺亚方舟),然后每隔1分钟海水会消退一层,在t 时刻,对于每座楼i,hi>t才会在水面上。只要看城市i左右城市的状态即可。

效率:O(n+m)

如果询问不是按照递增序列给出,得先将查询 排一下序,做完,再按照id 排一下序输出即可!

输入达10^6,加输入优化,发现速度快了400ms!!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define N 50
#define M 1000006
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
 
struct build{
  int h,id;
  bool operator <(const build &b)const{
    return h<b.h;
  }
}a;
int n,query[M];
bool vis[M];
priority_queue<build> Q;
int main()
{
    int T,m;
    scanf("%d",&T);
    for(int k=1;k<=T;k++)
    {
        while(!Q.empty())Q.pop();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a.h);
            a.id=i;
            Q.push(a);
        }
        for(int i=1;i<=m;i++)//m个查询时间,由小到大
            scanf("%d",&query[i]);
        int cnt=0;
        CLS(vis,0);
        for(int i=m;i>0;i--)
        {
            while(!Q.empty()&&Q.top().h>query[i])//将所有高出水面的楼全部处理掉!
            {
                int id=Q.top().id;
                Q.pop();
                if(vis[id-1]&&vis[id+1])cnt--;
                else if(!vis[id-1]&&!vis[id+1])cnt++;
                vis[id]=1;
            }
            query[i]=cnt;
        }
        printf("Case #%d:",k);
        for(int i=1;i<=m;i++)
            printf(" %d",query[i]);
        putchar('\n');
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值