17级2019春季个人训练赛-4 (含Strahler Order题解)

比赛地址  http://acm.sdibt.edu.cn/vjudge/contest/view.action?cid=2186#overview

A   Islands in the Data Stream

INPUT
4
1 0 0 1 1 2 2 1 1 0 1 2 2 1 1 0
2 0 1 2 3 4 3 2 1 2 3 4 3 2 1 0
3 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
4 0 1 2 3 4 5 6 7 6 5 4 3 2 1 0
output
1 4
2 7
3 7
4 7

题目与之前17级201917级2019春季个人训练赛-2比赛一个题重复

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6+7;
deque <char> dq;
stack <char> s;
int main()
{
    ll T,i,j,k,a[1010],ans=0,e;
    cin>>T;
    while(T--)
    {
        cin>>e;
        ans=0;
        memset(a,0,sizeof(a));
        for(i=1;i<=15;i++)
            cin>>a[i];
        for(i=1;i<=13;i++)
        {
            for(j=2;j<=15-i;j++)
            {
                ll minn=MAX;
                for(k=j;k<=j+i-1;k++)
                {
                    if(a[k]<minn)
                        minn=a[k];
                }
                if(a[j-1]<minn&&a[j+i]<minn)
                    ans++;
            }
        }
        cout<<e<<" "<<ans<<endl;
    }
    return 0;
}

B  Von Neumann's Fly

Input
5
1 250 10 15 20
2 10.7 3.5 4.7 5.5
3 523.7 15.3 20.7 33.3
4 1000 30 30 50
5 500 15 15 25
output
1 200.00
2 7.18
3 484.42
4 833.33
5 416.67

题意:每组给出四个数,D(甲乙两地路程总距离),A(A的速度),B(B的速度),F(飞机的速度)。让A从甲地出发到乙地,B从乙地出发到甲地,飞机从A出发,当遇到A或B时需要回头,问当AB相遇时,飞机走的总路程。

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6+7;
deque <char> dq;
stack <char> s;
int main()
{
    ll T,i,j,k,a[1010],ans=0,e;
    scanf("%lld",&T);
    while(T--)
    {
        //cin>>e;
        scanf("%lld",&e);
        double D,A,B,F;
        scanf("%lf%lf%lf%lf",&D,&A,&B,&F);
        double p=(double)D/(A+B);
        double ans=F*p;
        printf("%lld %.2lf\n",e,ans);
        //cout<<e<<" "<<ans<<endl;
    }
    return 0;
}

D  Pisano Periods

Input
5
1 4
2 5
3 11
4 123456
5 987654
output
1 6
2 20 
3 10
4 15456
5 332808

题意:每组样例的第2个数m,用斐波那契数组对它求余,求周期的长度。

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6+7;
deque <char> dq;
stack <char> s;
ll f[1000001]= {0};
int main()
{
    ll T,i,j,k,m,ans=0,e;
    cin>>T;
    while(T--)
    {
        cin>>e>>m;
        ll p=0,a=0,b=0;
        memset(f,0,sizeof(0));
        f[1]=1;
        f[2]=1;
        for(i=3; i<=1000000; i++)
        {
            f[i]=(f[i-1]+f[i-2])%m;
            if(f[i]==1&&f[i-1]==1&&f[i-2]==0)
            {
                cout<<e<<" "<<i-2<<endl;
                break;
            }
        }
    }
    return 0;
}

以上是比赛过程中做出来的。

E  Deranged Exams

Sample Input
4
1 4 1
2 7 3
3 10 5
4 17 17
Sample Output
1 18
2 3216
3 2170680
4 130850092279664

1)首先,至少前k个匹配错,做起来很麻烦,我们找它的对立事件:至多前k个对。

2)假设n=7, k=3:

     当计算前三个只有一个正确时,我们得到的情况数为 C(3,1)*A(6,6) ,即从前3个中选一个认为对,其他6个乱排。我们发现,这重复计算了有2个正确和有3个正确的情况,于是我们减去有2个正确的情况数C(3,2)*A(5,5),我们又发现这样多减掉了三个正确的情况,于是再加回来C(3,3)*A(4,4)。最终的到情况总数为 C(3,1)*A(6,6) - C(3,2)*A(5,5) + C(3,3)*A(4,4)。

以此类推,我们就得出了计算方式:取奇数时加,偶数时减,最终求出至多前k个对的情况数。

3)所求 = 所有情况数 - 至多前k个对的情况数 ,即 A(n,n) - sum。

4)下面的代码中,我用 a [ i ] 表示 i 的阶乘,先计算出了a 数组,因为1 ≤ N ≤ 17,用的时候直接取,不必重复计算,省时省力。

a [ k ] / ( a [ k - i ] * a [ i ] ) 就是C(k,i),排列组合公式。emmm... 记得开long long...
以上原文地址    https://blog.csdn.net/lxt_lucia/article/details/88534944   欢迎浏览~

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6+7;
ll a[25];
int main()
{
    ll T,i,j,k,n,ans=0,e;
    cin>>T;
    memset(a,0,sizeof(a));
    a[1]=1;
    a[0]=1;
    for(i=2;i<=20;i++)
        a[i]=a[i-1]*i;
    while(T--)
    {
        cin>>e>>n>>k;
        ans=0;
        for(i=1;i<=k;i++)
        {
            if(i%2!=0)
              ans+=(a[k]/(a[k-i]*a[i]))*a[n-i];
            else
              ans-=(a[k]/(a[k-i]*a[i]))*a[n-i];
        }
        cout<<e<<" "<<a[n]-ans<<endl;
    }
    return 0;
}

C - Strahler Order

Sample Input
1
1 7 8
1 3
2 3
6 4
3 4
3 5
6 7
5 7
4 7
Sample Output
1 3

题意 :有n个点,m条边,将入度为0的标记为1,然后如果有2个及以上的点是该点的前驱,那么这个点的等级为i+1,如果只有一个等级为i的是该点的前驱,这个点的等级就是i,求n个点中等级最大的点。

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6+7;
deque <ll> dq;
ll a[1010][1010];
ll du[1010]={0};
ll dj[1010]={0};
ll vis[1010]={0};
int tp(ll n)
{
    ll i;
    while(!dq.empty())
    {
        ll t=dq.front();
        dq.pop_front();
        if(vis[t]==1)//说明该点有两个或两个以上度数一样的前驱
            dj[t]++;
        for(i=1;i<=n;i++)//遍历找该点的后继
        {
            if(a[t][i]==1)
            {
                du[i]--;//符合时,每次将入度减一,最后入度为0时将该点放入队列中
                if(dj[i]==dj[t])//该点与它的前驱等级相等,只标记vis数组
                {
                    vis[i]=1;
                }
                if(dj[i]<dj[t])//该点比前驱等级小,vis清零,等级变为前驱的等级
                {
                    vis[i]=0;//不清零的话就不满足下面的例子
                    dj[i]=dj[t];
                }
            //举个例子,当一个点刚被遍历到时,它前驱的等级有2 2 3,所以会先执行第2个if.
            //然后执行第一个if,在执行第2个if,所以vis的作用就是标记它是否有两个及
            //以上前驱相同的点,等当从队列里取出的时候,只等级加一次。
                if(du[i]==0)
                    dq.push_back(i);
            }

        }
    }
    ll ans=-1;//找最大的等级
    for(i=1;i<=n;i++)
    {
        if(dj[i]>=ans)
            ans=dj[i];
    }
    return ans;
}
int main()
{
    ll T,i,j,k,n,m,ans=0,e,x,y;
    cin>>T;
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(du,0,sizeof(du));//点的入度
        memset(dj,0,sizeof(dj));//点的等级
        memset(vis,0,sizeof(vis));
        while(!dq.empty())
        {
            dq.pop_front();
        }
        cin>>e>>n>>m;
        for(i=0;i<m;i++)
        {
            cin>>x>>y;
            a[x][y]=1;
            du[y]++;
        }
        for(i=1;i<=n;i++)
        {
            if(du[i]==0)//先将入度为0的点放到队列中,并且将等级赋为1
            {
                dq.push_back(i);
                dj[i]=1;
            }
        }
        ll ans=tp(n);
        cout<<e<<" "<<ans<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值