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;
}
思路:
-
可以用O(n)的时间算好前缀和,之后就能在O(1)的时间计算区间上的总和。在确定起点s后,二分快速找出使得序列和不小于S的最近的终点就好了。算法复杂度是O(nlogn).
-
第二种方法是利用尺取法求解:
(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;
}