第二次训练赛题解 Earth_Pot_Chicken

A:简单的二分答案,二分面积就好,判断的时候看每个pie够分几个人,sum一下和来的人数判断。

由于这题没写过,这里附上rank1(90n)的代码,pi最好是acos(-1,0), 但他这里写的并不好,如果define的话,每次调用都要计算一次,直接写const double pi=acos(-1)。pi只手写3.1415926会出现精度问题,会WA。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include <math.h>
using namespace std;
#define pi acos(-1.0)
double v[10010];
int t,n,f,i;
int  pd(double x)
{
    int sum=0;
    for(i=0;i<n;i++)
    {
        sum+=(int)(v[i]/x);
    }
    return sum;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(v,0,sizeof(v));
        double l=0,r=0,mid;
        scanf("%d%d",&n,&f);
        f++;
        for(i=0;i<n;i++)
        {
            scanf("%lf",&v[i]);
            v[i]=pi*v[i]*v[i];
            l=min(l,v[i]);
            r=max(r,v[i]);
        }
        while(r-l>=1e-6)
        {
            mid=l+(r-l)/2;
            if(pd(mid)>=f)l=mid;
            else r=mid;
        }
        printf("%.4lf\n",mid);
    }
}

B:快速幂就好,或者找个循环节,计算量更小,循环节长度最多不超过10,因为状态有限。

这里附上本题一血的代码(rank2):

#include<bits/stdc++.h>
using namespace std;

int func(int n)
{
	int a=n;
	int b=1;
	while(a>0){
		if(a%2==1){
			b=b%10;
			n=n%10;
			b=b*n;
		}
		n=n%10;
		n=n*n;
		a=a>>1;
	}
	return b%10;
}
int main()
{
	int t;
	cin>>t;
	int m;
	while(t--){
		cin>>m;
		cout<<func(m)<<endl;
	}
	return 0;
}

C:题目大意:有n条绳子,长度分别为L[i]。如果从他们中切割出k条长度相同的绳子的话,这k条绳子每条最长能有多长?

二分答案,二分想要的绳子长度,每二分一次o(n)算可以获得多少个这样的绳子,再和y做比较就好。

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const double EPS=1e-9;
double n[N];
int main(){
    int x,y;
    cin>>x>>y;
    double maxn=0;
    for(int i=1;i<=x;++i){
        scanf("%lf",&n[i]);
        maxn=max(maxn,n[i]);
    }
    double l=0,r=maxn;
    int Cnt=1000;
    while(Cnt--){
        double mid=(l+r)/2;
        int cnt=0;
        for(int i=1;i<=x;++i)
            cnt+=n[i]/mid;
        if(cnt>=y)
            l=mid;
        else
            r=mid;
    }
    printf("%.2lf\n",floor(l*100)/100);
}

D: 上次比赛原题嘛:(没A的暴露了没补题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
double A[N],B[N];
int n;
double t;
double check(double x){
    double ans=0;
    for(int i=1;i<=n;++i){
    	if(B[i]+x<=0){
    		return t+1;
		}
        ans+=A[i]/(B[i]+x);
    }
    return ans;
}
int main(){
    cin>>n>>t;
    for(int i=1;i<=n;++i)scanf("%lf%lf",&A[i],&B[i]);
    double l=-1<<30,r=1<<30;
    for(int i=1;i<=1000;++i){
        double mid=(l+r)/2;
        if(check(mid)<=t)r=mid;
        else l=mid;
    }
    printf("%.9lf\n",l);
}

E:询问一个数x的第k大因子。

我们有个想法,从1枚举到x,看他能整除那个数就像这样:

for(int i=1;i<=x;++i){
    if(x%i==0){
        //do something
    }
}

对不起,复杂度o(n),当n>1e8是肯定超时,我们想到当x%i==0时,其实可以算出两个因数,一个是i,另一个是n/i,这样我们枚举到根号n就好了,复杂度是根号级别的,当x为1e15是,刚刚号不超过1e8,然后利用你喜欢的方式记录一下。

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long x;
    long long y;
    scanf("%lld%lld",&x,&y);
    set<long long> num;
    for(long long i=1;i*i<=x;++i){
        if(x%i==0){
            num.insert(i);
            num.insert(x/i);
        }
    }
    set<long long>::iterator it=num.begin();
    if(y>num.size()){
        cout<<"-1";
        return 0;
    }
    for(int i=1;i<y;++i){
        ++it;
    }
    cout<<*it;
}

F:题意:每门课最多翘两次,翘掉最大价值的两次课,求翘掉课的最大的价值。 

这道题直接贪心就好,其实是在考察STL库的使用:这里我使用了优先队列。

把每一门课开一个优先队列,这样这个队列的头总是这一门学科的最大值,然后贪心就好。(一年前写的代码,比较丑)

#include<bits/stdc++.h>
using namespace std;
char a[100][10];
int num=0;
int look(char b[]){
    int i;
    for(i=0;i<num;++i){
        if(strcmp(a[i],b)==0)
            return i;
    }
    ++num;
    strcpy(a[i],b);
    return i;
}
int main(){
    int x,y,z;
    cin>>x;
    while(x--){
        num=0;
        memset(a,0,sizeof(a));
        int ans=0;
        priority_queue<int> q[100];
        cin>>y;
        char s[10];
        while(y--){
            cin>>s>>z;
            q[look(s)].push(z);
        }
        for(int i=0;i<num;++i){
            ans+=q[i].top();
            q[i].pop();
            if(!q[i].empty())
                ans+=q[i].top();
        }
        cout<<ans<<endl;
    }
} 

G:题意:一个序列抽两个值,算mod p意义下的最大值。

我们可以用双针法在复杂度o(n)的情况下算出,输入后从小到大排个序,让左指针在最左边,右指针在最右边,如果这两个和小于p,++l,并更新一下可能的答案,如果超过p,--r,再更新答案就好,这样是保证在两个数加起来不超过p时的最大值,还有一种情况,就是两个数加起来大于p但mod p后还是最大的,那么可能情况只能时最大和次大加。

一血(90n)代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    long long int n,p,i,a[100010],l,r,zd;
    while(~scanf("%lld%lld",&n,&p))
    {
        memset(a,0,sizeof(a));
        for(i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
            if(a[i]>=p)a[i]%=p;
        }
        sort(a,a+n);
        l=0;r=n-1;
        zd=(a[n-1]+a[n-2])%p;
        while(l<r)
        {
            if((a[l]+a[r])>=p)r--;
            else
            {
                    zd=max(zd,a[l]+a[r]);
                    l++;
            }
        }
        printf("%lld\n",zd);
    }
}

H:Announcement上解释数论的逆元,其实就是当a和M互质时,a相对于M的逆元就是pow(a,M-2),所以这道题其实是快速幂,当然后边学到数论还会有另一种解法,扩展欧几里得的解法,感兴趣的可以先自行百度。

一血代码( yuhao007):扩展欧几里得的做法

#include<stdio.h>
int x,y;
void gcd(int a,int b)
{
	int t;
	if(b==0)
	{
		x=1;
		y=0;
		return;
	}
	else 
	{
		gcd(b,a%b);                            
        t=x;
        x=y;
        y=t-(a/b)*y;
	}
}
main()
{
	int T,n,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		gcd(m,9973);
		if(x<0)
		x+=9973;
		x*=n;
		printf("%d\n",x%9973);
	}
	return 0;
}

二血代码(90n):快速幂做法:

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
typedef long long int lli;
lli ksm(lli b)
{
    lli y=1,a=9971;
    b=b%9973;
    while(a)
    {
        if(a&1)y=(y*b)%9973;
        b=b*b%9973;
        a/=2;
    }
    return y;
}
int main()
{
    int t;
    lli a,b,f;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&a,&b);
        b=ksm(b);
        f=a*b%9973;
        printf("%lld\n",f);
    }
}

I:是没有办法直接算阶乘的位数的,但是取个log,乘法不就是加法了,而log10表示的也恰好是位数:一血( chenghao2000324)的代码:

#include<stdio.h>
#include<math.h>
int main()
{
    long n,p,t;scanf("%d",&t);
    for(p=0;p<t;p++)
    {
        scanf("%d",&n);
        double s=0;
        int s1=0;
        int i; 
        for(i=1;i<=n;i++)
        {
        	s+=log10(i);
        	s1=(int)s;
		}  
		printf("%d\n",s1+1);
    }
    return 0;
}

J: 水题不讲了

一血者(hheeeeee)的代码:

#include<stdio.h>
int main()
{
    int n;
    int a[102]={0};
    while(scanf("%d",&n)!=EOF)
    {
        int t=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(i==0)
            {
                t+=a[i]*6;
            }
            else
            {
                if(a[i]>a[i-1])
                {
                    t+=(a[i]-a[i-1])*6;
                }
                else
                {
                    t+=(a[i-1]-a[i])*4;
                }
            }
            t+=5;
        }
        if(n==0)
        {
            break;
        }
        else
        {
            printf("%d\n",t);
        }
    }
    return 0;
}

K: 折半枚举+HASH储存,防AK题,暴力枚举150^6肯定超时,我们可以这样,先暴力前一半150^3,记录到某种容器里,其实最方便的时map容器,但是复杂度多一个log,会超时,这里只能用hash table,然后再枚举后一半又是150^3,每次枚举完到容器里找到相加等于0的个数就好,这样复杂度150^3+150^3肯定不会超时,对这半枚举感兴趣的,了解一下2013年国家集训队论文集的《搜索问题中的 meet in the middle 技巧》江苏南京外国语学校 乔明达。

#include<iostream>
#include<map>
#include<cmath>
using namespace std;
const int M=12313813;
int n,m,K[100],P[100],ans;
int Pow[200][200];
struct Hash{
	int value,num;
}H[M+10];
inline int HASH(int x){
	int y=x<0?-x:x;
	y%=M;
	while(H[y].num>0&&H[y].value!=x)y=(y+1)%M;
	return y;
} 
void dfs1(int x,int a){
    if(x==n/2+1){
        int h=HASH(a);
        H[h].value=a;
        H[h].num++;
        return;
    }
    for(int i=1;i<=m;++i){
        dfs1(x+1,a+K[x]*Pow[i][P[x]]);
    }
}
void dfs2(int x,int a){
    if(x==n+1){
        ans+=H[HASH(-a)].num;
        return;
    }
    for(int i=1;i<=m;++i){
        dfs2(x+1,a+K[x]*Pow[i][P[x]]);
    }
}
int main(){
    for(int i=1;i<=150;++i){
        Pow[i][0]=1;
        for(int j=1;j<=100;++j)Pow[i][j]=Pow[i][j-1]*i;
    }
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>K[i]>>P[i];
    if(n==1){
    	for(int i=1;i<=m;++i){
    		if(Pow[i][P[1]]*K[1]==0)++ans;
		}
		cout<<ans<<endl;
		return 0;
	} 
    dfs1(1,0);
    dfs2(n/2+1,0);
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/Gipsy_Danger/article/details/83244667
今日推荐