Gym 101243 (2016-2017 ACM Central Region of Russia Quarterfinal Programming Contest)

这篇博客详细解析了ACM Central Region of Russia Quarterfinal Programming Contest中的几道题目,包括煎鱼问题的最优化解决方案、汉诺塔的规律探索、桌面覆盖问题的策略以及天气站、蛋糕分配和数字构造等题目的思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem A B C D E G H are included.

A. Fried Fish

题意:

         N 条鱼要煎熟,每次煎鱼锅中只能煎 K 条鱼的一面(一条鱼要煎两面),问最少要煎几次?

思路:

         由于一次只能煎鱼身的一面,故最少要煎两次。max(2,ceil(n*2/k))即可

代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    double n,m;
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    while(cin>>n>>m){
        cout<<max(ceil(n*2.0/m),2.0)<<endl;
    }
}

B. Hanoi tower

题意:

         本题题意与样例似乎有矛盾,我觉得题目应该是这样的:

         问 N 个盘子的汉诺塔,在第几次移动时,三根柱子上的盘子数一样。保证 N%3==0。

         当 N == 3的时候,答案是 2。

思路:

         先跑一边汉诺塔,打表找规律。发现

         A[3] = 2 , A[6] = 9

         当 N 是奇数时 A[N] = A[N-3] * 4 + 2

         当 N 是偶数时 A[N] = A[N-3] * 4 -TMP[N];TMP[12]=17 TMP[N]=TMP[N-6]*4+21;

代码:

汉诺塔:

#include <iostream>
#include <stdio.h>
using namespace std;
long long ans;
string steps;
int cut[3];
bool flag;
string add(string str1,string str2){
    int len1=str1.size();
    int len2=str2.size();
    if(len1<len2){
        swap(str1,str2);
        swap(len1,len2);
    }
    int c=0;
    for(int i=len1-1,j=len2-1;i>=0;i--,j--){
        int temp=0;
        if(j>=0)
            temp+=str2[j]-'0';
        temp+=str1[i]+c-'0';
        str1[i]=temp%10+'0';
        c=temp/10;
    }
    if(c)
        str1='1'+str1;
    return str1;
}
void judge(){
    if(cut[0]==cut[1]&&cut[1]==cut[2]){cout<<steps<<endl;flag=0;}
}
int move(int x,char a,char b)
{
    cut[a-'A']--;cut[b-'A']++;
    steps=add(steps,"1");judge();
    //for(int i=0;i<3;i++)
        //cout<<cut[i]<<endl;
    //printf("number..%d..form..%c..to..%c\n",x,a,b);
}

int mission(int x,char a,char b,char c)
{
    if(!flag) return 0;
    if(x==1)
    move(1,a,c);
    else
    {
        mission(x-1,a,c,b);//将x-1从a借c移到b。
        move(x,a,c);
        mission(x-1,b,a,c);//将x-1从b借a移到c。
    }
    return 0;
}
int main()
{
    int n;
    for(int i=1;i<=100;i++)
    {
        n=i*3;
        flag=1;
        steps="0";
        cut[0]=n;cut[1]=cut[2]=0;
        mission(n,'A','B','C');
    }
    return 0;
}
递推:

import java.math.*;
import java.util.*;
import java.io.*;
public class main {
	public static void main(String[] args) {
//		FOR First JAVA AC 2333333333
		
		try{
			Scanner cin = new Scanner(new File("input.txt"));
			FileWriter out = new FileWriter(new File("output.txt"));
			int n;
			File file = new File("INPUT.TXT");
			BigInteger ans[] = new BigInteger[200];
			ans[1] = new BigInteger("2");
			ans[2] = new BigInteger("9");
			BigInteger FOUR = new BigInteger("4");
			BigInteger TWO = new BigInteger("2");
			BigInteger TMP = new BigInteger("17");
			BigInteger TW = new BigInteger("21");		
			for(int i=3;i<=100;i++){
				ans[i]=ans[i-1].multiply(FOUR);
				if(i%2==1){
					ans[i]=ans[i].add(TWO);
				}else{
					ans[i]=ans[i].subtract(TMP);
					TMP=TMP.multiply(FOUR);TMP=TMP.add(TW);
				}
			}
			while(cin.hasNext()){
				n = cin.nextInt();
				out.write(ans[n/3].toString());
			}
			out.close();
		}catch(Exception e){
			
		}
	}
}

C. Desktop

题意:

        给出一个 N × M 的矩阵,用2×2的矩阵去覆盖它,覆盖的矩阵可以重叠但至少需要露出一半的面积。询问最大能放多少个2×2矩阵并且给出一种方案 

思路:

        很容易想到类似鱼鳞形状的铺法层铺。但要使数量最多,存在两个问题(以每一行作为铺设方向为例)

        1.若行数或列数为奇数,直接鱼鳞状铺法只能浪费掉一行或一列。所以我们要把奇数行或奇数列两两间不重叠地铺好。

        2.铺好后最后一层会有浪费,故最后一层要反向地铺。即若是以行铺,那最后一层以列铺,若是以列铺,那最后一层以行铺

#include<bits/stdc++.h>
using namespace std;
#define MAXN 500010
int cut,x[MAXN],y[MAXN];
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n,m;
    while(cin>>n>>m){
        if(n<2||m<2){cout<<0<<endl;continue;}
        int cut=0;
        if(m%2){
            for(int i=1;i<n;i+=2){
                cut++;x[cut]=i;y[cut]=m-1;
            }
            m--;
        }
        if(n%2){
            for(int i=1;i<m;i+=2){
                cut++;x[cut]=n-1;y[cut]=i;
            }
            n--;
        }
        for(int i=1;i<=n;i+=2){
            for(int j=1;j<m-1;j++){
                cut++;x[cut]=i;y[cut]=j;
            }
        }
        for(int i=1;i<n;i++){
            cut++;x[cut]=i;y[cut]=m-1;
        }
        cout<<cut<<endl;
        for(int i=1;i<=cut;i++)
            cout<<x[i]<<' '<<y[i]<<endl;
    }
}


D. Weather Station

题意:

        给出1个字符串,由8各方向组成,问按照字符串从左到右的顺序,能有几种不同的走法。

思路:

        小DP,显然要想形成不同的路径,只有在串中出现 NE,SE,NW,SW时才会发生。

        而每当出现这些子串时(以NE为例),我们有两种选择

             1.继承 NE 串前面的状态,将NE看成一步。

             2.继承 E 前面的状态,将 N E看成两步。

        这两种选择都要加入DP计算

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#define mod 1000000007

using namespace std;

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    char str[100005];
    int ans[100005],len;
    while(cin>>str)
    {
        ans[0]=ans[1]=1;
        len=strlen(str);
        for(int i=1;i<len;i++)
        {
            if((str[i]=='E'||str[i]=='W')&&(str[i-1]=='N'||str[i-1]=='S'))
                ans[i+1]=(ans[i-1]+ans[i])%mod;
            else
                ans[i+1]=ans[i];
        }
        cout<<ans[len]<<endl;
    }
    return 0;
}
E. Cupcakes

题意:

         N 个人以循环队列的方式要分吃 K 个蛋糕。给出每次第 i 个人最多吃 a[i] 个蛋糕(即每次可以吃1~a[i]),若轮到某个人时已经没有蛋糕了,那这个人要负责收拾桌子。

         现在。同学们希望让那个每次都要吃最多蛋糕的人收拾桌子,因为他每次不仅能吃的最多,且每次都要吃 a[i] 个。问其他同学是否可以齐心协力通过调节自己吃的量,使得那个吃的最多的人收拾桌子。
思路:

        由于每一轮同学们吃的蛋糕的量的范围是确定的,所以蛋糕的余量在某一轮的范围内,就可以做到,反之则不能。

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+100;
long long a[MAXN],n,m,all;
long long front,left1,left2,turn1,turn2,temp1,temp2,temp3;
int pos;
bool solve(){
    if(pos<=m&&front>=m) return 1;
    left1=m-front;left2=m-pos;
    turn1=n+a[pos]-1;turn2=all;
    temp3=0;
    for(int i=1;;i++){
        temp1=turn1*i;
        temp2=turn2*i;
        if(left2<temp1) return 0;
        if(temp3>temp1) return 1;
        else temp3=temp2;
        if(temp2<left1) continue;
        else return 1;
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);
    while(cin>>n>>m){
        front=0;
        all=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            all+=a[i];
        }
        pos=max_element(a,a+n)-a;
        for(int i=0;i<pos;i++)
            front+=a[i];
        if(solve()) cout<<"YES"<<endl;
        else cout<<"KEK"<<endl;
    }
}
G. Sphenic numbers

题意:

         给出一个数,问是否可以由三个(种?)质数相乘得到。

思路:

         若严格要求是三个质数,我的思路是打出质数后,暴力+剪枝完成.

         若只是要求是三种质数,跑一边素数筛,记录每个数被筛到的次数就行。

代码:

三个质数:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN=1e7+100;
int prime[(int)1e7+5];
void getP()
{
    memset(prime,0,sizeof(prime));
    for(int i=2; i<=MAXN; i++)
    {
        if(!prime[i])prime[++prime[0]]=i;
        for(int j=1; j<=prime[0]&&prime[j]<=MAXN/i; j++)
        {
            prime[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
bool t[11000000]={0};
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int cur1=0,m;
    getP();
    for(int i=1;i<300000;i++)
    {
        if(prime[i]*prime[i]*prime[i]>10467397)
            break;
        for(int j=i+1;j<300000;j++)
        {
            if(prime[i]*prime[j]*prime[j]>10467397)
                break;
            for(int k=j+1;k<300000;k++)
            {
                if(prime[i]*prime[j]*prime[k]>10467397)
                    break;
                if(!t[prime[i]*prime[j]*prime[k]])
                    t[prime[i]*prime[j]*prime[k]]=1;
            }
        }
    }
    while(cin>>m)
    {
        if(t[m])
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}
三种质数:
#include <bits/stdc++.h>

using namespace std;

int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n;bool flag;
    while(cin>>n){
        int cut=0;
        for(int i=2;i*i<=n;i++){
            flag=1;
            while(n%i==0){
                if(flag){cut++;flag=0;}
                n/=i;
            }
        }
        if(n!=1) cut++;
        if(cut==3) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}
H. Non-random numbers

题意:

        求从左向右没有前置0,第一位不能有1,第二位不能有2........第九位不能有9的 N 位数的个数。

思路:

        规律题

代码:

#include <bits/stdc++.h>

using namespace std;
long long ans[10]={0};
int n;
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    ans[1]=8;
    for(int i=2;i<=9;i++) ans[i]=ans[i-1]*9;
    while(cin>>n){
        cout<<ans[min(9,n)];
        for(int i=10;i<=n;i++) cout<<'0';
        cout<<endl;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值