C1 4th Round

A - The 3n + 1 problem
水题

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
    int m,n;
    while(cin>>m>>n){
        cout<<m<<" "<<n<<" ";
        if(m>n)swap(m,n);
        int maxn=0;
        for(int i=m;i<=n; i++){
            int num=0;
            int c=i;
            while(c!=1){
                if(c%2==0){
                    c=c/2;
                }
                else{
                    c=3*c+1;
                }
                num++;
            }
            if(num>maxn){
                maxn=num;
            }
        }
        cout<<maxn+1<<endl;
    }
    return 0;
    }

B - Subsequence
题意:给定长度为n的整数数列a0,a1,…,an-1以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,输出0。
判断:就是超时,而电脑。。。它双标我。。。
百度判断:1、二分查找法
2、尺取法
直接上(尴尬了,这就是尺取法)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100005];
int n,s;
int main(){
    int N;
    cin>>N;
    while(N--){
        cin>>n>>s;
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        int num=1000000;
        for(int i=0,j=0,sum=0;i<n;i++){
             while(sum<s&&j<=n-1){
                    sum+=a[j];
                    j++;
             }
             if(sum>=s)
                {num=min(j-i,num);}
                sum-=a[i];//避免重复加,减少时长
        }
        if(num==1000000)
            cout<<"0"<<endl;
        else
        cout<<num<<endl;
    }
    return 0;
}

思路:

  1. 可以用O(n)的时间算好前缀和,之后就能在O(1)的时间计算区间上的总和。在确定起点s后,二分快速找出使得序列和不小于S的最近的终点就好了。算法复杂度是O(nlogn).

  2. 第二种方法是利用尺取法求解:

(1).以s=t=sum=0初始化。

(2).只要依然有sum<S,就将sum增加ai,并将t增加1。

(3).如果(2)中无法满足sum>=S则终止。否则的话,更新res=min(res,t-s).

(4).将sum减去as,s增加1后回到(2).

算法的复杂度是O(n)。

前缀和+二分搜索
————————————————
版权声明:本文为CSDN博主「luciozhang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_18738333/article/details/48804381

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 100005;

int num[MAXN];
int sum[MAXN];
int n, s;

int main()
{
	int casen;
	scanf("%d", &casen);
	while (casen--)
	{
		scanf("%d%d", &n, &s);
		for (int i = 0; i < n; i++)
			scanf("%d", &num[i]);
		sum[0] = num[0];
		for (int i = 1; i < n; i++)
			sum[i] = sum[i - 1] + num[i];//保证数组从小到大
		if (sum[n - 1] < s)
		{
			printf("0\n");
			continue;
		}
		int ret = n;
		int b, e;
		for (b = 0; sum[b] + s  <= sum[n-1]; b++)
		{
			e = lower_bound(sum + b, sum + n, sum[b] + s) - sum;//从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
			ret = min(ret, e - b);
		}
		printf("%d\n", ret);
	}
}
这是一个有漏洞的题解,震惊于交上去也能对,这个方法忽略了第一个数就达到s的可能性

C - Die
判断:水题,但是麻烦自己单词不要拼错

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main(){
    char a[9];
    string str1,str2,str3;
    cin>>str1>>str2>>str3;
    for(int i=0;i<3;i++){
    int o=0,p=3,q=6;
    a[o+i]=str1[i];
    a[p+i]=str2[i];
    a[q+i]=str3[i];
    }
    if(a[0]==':'&&a[1]==':'&&a[2]==':'&&a[3]==':'&&a[4]=='o'&&a[5]==':'&&a[6]==':'&&a[7]==':'&&a[8]==':')
        cout<<"1"<<endl;
    else  if(a[0]=='o'&&a[1]==':'&&a[2]==':'&&a[3]==':'&&a[4]==':'&&a[5]==':'&&a[6]==':'&&a[7]==':'&&a[8]=='o')
        cout<<"2"<<endl;
    else  if(a[0]==':'&&a[1]==':'&&a[2]=='o'&&a[3]==':'&&a[4]==':'&&a[5]==':'&&a[6]=='o'&&a[7]==':'&&a[8]==':')
        cout<<"2"<<endl;
    else  if(a[0]==':'&&a[1]==':'&&a[2]=='o'&&a[3]==':'&&a[4]=='o'&&a[5]==':'&&a[6]=='o'&&a[7]==':'&&a[8]==':')
        cout<<"3"<<endl;
    else  if(a[0]=='o'&&a[1]==':'&&a[2]==':'&&a[3]==':'&&a[4]=='o'&&a[5]==':'&&a[6]==':'&&a[7]==':'&&a[8]=='o')
        cout<<"3"<<endl;
    else  if(a[0]=='o'&&a[1]==':'&&a[2]=='o'&&a[3]==':'&&a[4]==':'&&a[5]==':'&&a[6]=='o'&&a[7]==':'&&a[8]=='o')
        cout<<"4"<<endl;
    else  if(a[0]=='o'&&a[1]==':'&&a[2]=='o'&&a[3]==':'&&a[4]=='o'&&a[5]==':'&&a[6]=='o'&&a[7]==':'&&a[8]=='o')
        cout<<"5"<<endl;
    else  if(a[0]=='o'&&a[1]==':'&&a[2]=='o'&&a[3]=='o'&&a[4]==':'&&a[5]=='o'&&a[6]=='o'&&a[7]==':'&&a[8]=='o')
        cout<<"6"<<endl;
    else  if(a[0]=='o'&&a[1]=='o'&&a[2]=='o'&&a[3]==':'&&a[4]==':'&&a[5]==':'&&a[6]=='o'&&a[7]=='o'&&a[8]=='o')
        cout<<"6"<<endl;
    else cout<<"unknown"<<endl;
    return 0;

}

D - Forest for the Trees
题目:https://open.kattis.com/problems/forestforthetrees
判断:过于暴力会超时,所以要找简化规律,第一找最小的整树点,然后就好判断了

#include <iostream>
using namespace std;
long long x,y,x1,ym,x2,y2;
inline long long gcd(long long a,long long b){
    return b>0?gcd(b,a%b):a;//欧几里得算法
}
bool panduan(long long a,long long b){
    if(a==x&&b==y)
        return true;
    if(a==0&&b==0)
        return true;
    if(a>=min(x1,x2)&&a<=max(x2,x1)&&b>=min(ym,y2)&&b<=max(y2,ym))
        return true;
    return false;
}
int main()
{
    cin>>x>>y>>x1>>ym>>x2>>y2;
    long long t=gcd(x,y);//返回最大公约数
    long long ax=x/t,ay=y/t;
    if(panduan(ax,ay)&&panduan(x-ax,y-ay)){//去掉公约数,就是最小正整数树点,如果第一个和最后一个都在里面,那么全程无遮挡
    }else{
        cout<<"No"<<endl;//接下来找到第一个无遮挡点
        if(!panduan(ax,ay)) cout<<ax<<" "<<ay;//如果第一个互质的数就遮挡了,那么直接输出
        else{//找到最小被遮挡倍数
            long long dis=min(x2/ax,y2/ay);//最小倍数
            dis++;//要加一,找规律
            cout<<dis*ax<<" "<<dis*ay;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值