您的位置:首页 > 其它

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

2014-07-22 19:23 393 查看
妥妥的被虐,第一题其实就是猜出来的,第二题错好了好多发,最后乱改压时间过了,实际上是自己粗心写错了地方。。。。

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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: