被虐中成长——2014年多校训练赛第一场解题报告

47 篇文章 0 订阅
13 篇文章 0 订阅

妥妥的被虐,第一题其实就是猜出来的,第二题错好了好多发,最后乱改压时间过了,实际上是自己粗心写错了地方。。。。

A题,看了赛后解题报告才知道是什么费马小定理,我们是自己列出数据算发现的规律,只有第i个(i%(p-1)==0)的球有分数,所以计算有几个有分数的球就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
	int n,p;
	while(~scanf("%d%d",&n,&p))
	{
		int ans;
		ans=n/(p-1);
		if(ans%2==1)
		{
			cout<<"YES"<<endl;
		}
		else
		{
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

D题Task

有n台机器最大工作时间是t,最高难度是l,m个任务,工作时间是t,难度是l,每个任务只能由一台机器完成,每个机器只能完成一个任务,每个任务的赏金是500*t+2*l,求最多能得到多少赏金,输出完成的任务的个数以及赏金。

数据量很大,很容易T,做法应该是让每一个机器完成时间最相近的任务,刚开始没找到思路乱搞一直T or WA。

最后做法是:根据l的级别做,开1440个栈对应需要多少时间的任务,l的等级从1到100,每次把对应等级的任务压进所需要时间的栈,然后搜索该等级的机器最大能完成的任务,直接搜时间即可,然后把这个出栈,继续下一个机器,直到等级大于i。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100010
#define eps 1e-7
#define INF 0x7FFFFFFF
#define ff sqrt(5.0)
typedef long long ll;
struct node
{
    int t;
    int l;
}task[110000],mach[110000];
int n,m;
stack<int>s[1500];
bool cmp(node a,node b)
{
    if(a.l==b.l) return a.t<b.t;
    return a.l<b.l;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&mach[i].t,&mach[i].l);
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&task[i].t,&task[i].l);
        }
        sort(mach,mach+n,cmp);
        sort(task,task+m,cmp);
		for(int i=0;i<1500;i++)
        {
           while(!s[i].empty())
           {
           	s[i].pop();
           }
        }
        int p,q;
        int cnt=0;
        long long ans=0LL;
        p=0;
        q=0;
        for(int i=0;i<=100;i++)
        {
            while(task[p].l<=i&&p<m)
            {
                //cout<<task[p].l<<endl;
                s[task[p].t].push(task[p].l);
                p++;
            }
            while(mach[q].l<=i&&q<n)
            {
                for(int j=mach[q].t;j>=0;j--)
                {
                    if(!s[j].empty())
                    {
                        int tmp=s[j].top();
                        s[j].pop();
                        cnt++;
                        ans+=tmp*2+500*j;
                        break;
                    }
                }
                q++;
            }
        }
        cout<<cnt<<" "<<ans<<endl;
    }
}

I题 Turn the poker(组合数)(赛后)
翻纸牌游戏,给出操作次数n和纸牌数目m,每次操作选择x张智牌翻转,问最后牌的结果有多少种情况。

把最开始的牌都认为处于0状态,翻转后变为1,最后的答案就是ans=∑C(m,k),C(m,k)为组合数,k为所有能取到的1的可能个数。详细的解释,先了解最后1的个数的奇偶性,跟所有翻牌数的和的奇偶相同(每次翻牌,要么0->1,要么1->0,都是在改变1的个数奇偶)。之后我们需要找到最少有i个1,以及最大有j个1;i的情况就是有1就翻1,j的情况就是有0就翻0,而中间的情况时,取偶数步数,一半翻0,一半翻1,保持不变,所以可以确定i,i+2,i+4,...,j-2,j都能被翻到。最后ans=∑C(m,k)(i<=k<=j&&k%2==i%2)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <ctime>
#define ll __int64
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+9;
ll c[maxn];
ll pow_mod(ll a ,ll b)
{
    ll s=1;
    while(b)
    {
        if(b&1)
        {
            s=s*a%mod;
        }
        a=a*a%mod;
        b=b>>1;
    }
    return s;
}
int main()
{
    int n,m;
    int x;
    int p,q;
    int high,low;//上下限 
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        high=0;
        low=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            if(low>=x)
            {
                p=low-x;
            }
            else if(high>=x)
            {
                p=((low&1)==(x&1)?0:1); 
            }
            else
            {
                p=x-high;
            }
            if(high+x<=m)
            {
                q=high+x;
            }
            else if(low+x<=m)
            {
                q=(((low+x)&1)==(m&1)?m:m-1);
            }
            else
            {
                q=2*m-(low+x);
            }
            low=p;
            high=q;
        }
        ll ans=0;
        c[0]=1;
        if(low==0)
        {
            ans+=c[0];
        }
        for(int i=1;i<=high;i++)
        {
            if(m-i<i)
            {
                c[i]=c[m-i];
            }
            else
            {
                c[i]=c[i-1]*(m-i+1)%mod*pow_mod(i,mod-2)%mod;
            }
            if(i>=low&&(i&1)==(low&1))
            {
                ans+=c[i];
            }
        }
          printf("%I64d\n",ans%mod); 
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值