好多贪心啊。
A. Circle of Students
题目大意:
一群学生围成一个圈跳舞,每个学生都有一个编号,如果n个学生围成一个圈后,无论顺时针或者逆时针,总能依次从 1号到n号。
则输出"YES",否则输出"NO"
第一种做法:
直接模拟一下就行了,找出1号的位置,然后看2号在其顺时针方向还是逆时针方向,依次遍历,如果不符合条件,输出,跳出循环。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main(){
int T;
cin>>T;
int f = 0;
while(T--){
f++;
int A[205];
memset(A,0,sizeof(A));
int t;
cin>>t;
for(int i = 0; i < t; i++){
cin>>A[i];
}
if(t==1&&A[0]==1) cout<<"YES\n";
else{
int cnt = 0, count = 1;
int i = 0;
for(i = 0; i < t;i++){ // 找到 1号的位置, 并判断应该顺时针遍历还是逆时针遍历
if(A[i]==1){
if(i==t-1) {
if(A[i-1]-A[i]==1)
cnt = -1;
else cnt = 1;
break;
}
else{
if(A[i+1] - A[i] ==1){
cnt = 1;
}
else
cnt = -1;
break;
}
}
}
if(cnt==1) {
int j = 0;
while(count!=t){
if(i<t-1) j = i + 1;
else j = 0;
// cout<<A[j]<<" " <<A[i]<<endl;
if(A[j] - A[i] != 1) break;
else count++;
if(i==t-1&&j==0) {i = j; j++;}
else {i++;}
// cout<<count<<" ----"<<endl;
}
}
else if(cnt==-1){
int j = 0;
while(count!=t){
if(i>0)
j = i - 1;
else j = t - 1;
if(A[j] - A[i] != 1) break;
else count++;
if(i==0&&j==t-1) {i = j; j--;}
else i--;j--;
}
}
if(count==t) cout<<"YES\n";
else cout<<"NO\n";
// cout<<f<<"/"<<endl;
}
}
return 0;
}
第二种做法:
不需要考虑方向,如果能按1~n的顺序围成一个圈,那么,两个相邻的人的编号之差的绝对值要么是1 要么是n-1 。
所以判断n个编号是否全都满足以上条件。
如 3 2 1 4 3-2=1 2-1=1 4-1=3
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main(){
int T;
cin>>T;
while(T--){
int f = 0,t;
int A[205];
memset(A,0,sizeof(A));
cin>>t;
for(int i = 0; i < t; i++) cin>>A[i];
for(int i = 0; i < t - 1; i++){
if(abs(A[i]-A[i+1])!=1&&abs(A[i]-A[i+1])!=t-1) {
f = 1;
break;
}
}
f ? cout<<"NO\n" : cout<<"YES\n";
}
return 0;
}
B.Equal Rectangles
题目大意:
给出4n条边,让你组成n个面积相等的矩形,如果能组成,则输出"YES",否则输出"NO"
首先判断是否能组成n个矩形
条件1:构成一个矩形的条件是,有两对相等的边,所以构成n个矩形的条件是 有2*n对相等的边。
再判断n个矩形的面积是否能相等。
一共有2*n个对边,如果想组成 n 个面积相等的矩形,则最长对边只能与最短对边组成一个矩形,然后除去这两组对边后的最长边和最短边再次组成一个矩形,如果有面积不同的,则不能够成n个面积相等的矩形。
证明: 反正法:设最长边为 la 最短边为 lb 其他任意边为 lc 则 la > lc > lb
设最长边和除了最短边外任意一组对边组合为矩形A,面积为Sa, Sa = la*lc
最短边和除了最长边外任意一组对边组合为矩形B,面积为Sb,Sb = lc*lb
则 la*lc > lc*lb, 即此种情况两矩形面积永远不可能相等。 所以最长边只能与最短边组合。
#include <stdio.h>
#include <iostream>
#include <queue>
#include <string>
#include <algorithm>
#include <cstring>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int T, flag = 1, A[10002]={0}, B[420]={0}; //A数组用来记录每条边出现的次数
cin>>T; //B数组用来保存每组对边。
int j = 0;
for(int i = 0; i < 4*T; i++) {
int x;
cin>>x;
A[x]++;
if(A[x]%2==0){
B[j++] = x;
}
}
sort(B,B+j);
int cnt = B[0]*B[j-1];
if(j!=2*T) {cout<<"NO\n";continue;}
for(int i =1,k = j-2; i<j/2;i++,k--){ //让最大边和最小边进行组合才有可能满足条件
if(B[i]*B[k]!=cnt) {flag = 0; break;}
}
flag ? cout<<"YES\n" : cout<<"NO\n";
}
return 0;
}
C.Common Divisors
题目大意:
给出n个整数,找出所有能被n个数整除的数。
即找出n个数的最大公约数,然后求其因子个数。
__gcd()为库函数
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
#define sscc ios::sync_with_stdio(false)
using namespace std;
int main(){
sscc;
long long a;
cin>>a;
long long x,y;
cin>>x;
long long cnt = 0;
for(long long i = 1; i < a; i++){cin>>y; x = __gcd(x,y); }
for(long long i = 1; i <= sqrt(x); i++) if(x%i==0) cnt++,cnt++;
if((long long )sqrt(x) == sqrt(x)) cout<<cnt-1;
else cout<<cnt;
return 0;
}
D. Remove the Substring
题目大意 :
给出两个字符串, s和t, 保证 t 一定是 s 的子串。 然后在s中删除一些子序列后, 要使 t 仍是s 的子串, 求删除子序列的最长长度为多少。
也就是求通过删除s中的一些子序列将 s 变为 t 后,所删除的最长子序列。
那么分析如何删除子序列,
一共只有两种删法。设 t = ab
第一: 删去 在 s 串中 t 串左右两端的子序列, 求MAX. 如: baaba 可删去的最大长度为 2
第二: 删去 在 s 串中 组成 t 串的字符之间的子序列, 求MAX, 如: aaabb 可删去的最大长度为3
最后在比较两种删法的MAX。
那么如何求呢?
对于第一种, 求右端最长可删去子序列,则s中的t串要尽可能靠左, 如 babba s[1] 和 s[2] 可以组成 t, s[1]和s[3] 同样可以组成 t ,显而易见肯定选择前者。
当从左向右遍历时s串时,所有第一次和t串匹配的字符,所构成的 t 串,则是距离右端最远的。
当从右向左遍历时s串时,所有第一次和t串匹配的字符,所构成的 t 串,则是距离左端最远的。
示例: s = aaaaccccdddddddf t = acd
则 aaaaccccddddddddf 这三个位置构成的 t 距离右端最远。 aaaaccccddddddddf 这三个位置构成的 t 距离左端最远
一个离左端最远,一个离右端最远,所以两者相减,就是第二种删法所求的最大值。
即 aaaaccccddddddddf a c 字符之间可最长删去6个字符。
aaaaccccdddddddf c d 字符之间可最长删去9个字符。
所以MAX = 9
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
using namespace std;
const int N = 2*1e5+5;
int arr1[N];
int arr2[N];
// 满足条件 -> next[i] 严格小于 next[i+1];
char s[2*N],t[2*N]; // baaba ab 2 4 3 4 从左开始第一个满足条件的数
//abcccdefgfffggasdaswezxcggg abcfg 1238 12 125 11 12
int main(){
scanf("%s",s+1);
scanf("%s",t+1);
int len1 = strlen(s+1);
int len2 = strlen(t+1);
int Max = 0;
for(int i = 1,j = 1; i <= len1&&j<=len2; ){
if(s[i]==t[j]){ //记录了从左到右t中每个字母在s中出现的首位置。
arr1[j] = i;
++i,++j;
}
else ++i;
}
for(int i = len1,j = len2; i >= 1&&j >= 1; ){
if(s[i]==t[j]){ //记录了从右到左t中每个字母在s中出现的首位置。
arr2[j] = i;
--i,--j;
}
else --i;
}
/第二种删法。
for(int i = 1; i < len2; i++){
Max = max(Max, arr2[i+1] - arr1[i] -1); // 右边的减左边的 baaba
}
Max = max(Max,arr2[1]-1); // 第一种删法的左右两端情况。
Max = max(Max,len1-arr1[len2]);
printf("%d",Max);
return 0;
}
E. Boxers
题目大意:
给出n个数,代表 n 个拳击手的初始体重。
要求在比赛的时候组成一队所有拳击手体重都不同的队伍, 赛前拳击手的体重可以增加一或减一,但最低为1。
求这一队最多可以有几个拳击手。
也就是说给出n个数, 这n个数可以改变加一或减一,但不能变为0,求最多可以改变为多少个不同的数。
为了尽可能的避免将某个数变化后和其他数重复,则将最大数加+1,现在得到的数一定不会和其他数重复,那么就空出了一个数,所以第二大的数加一去填补,就又空出了一个数,依次类推,如果有重复的,就不加,还有重复的就减一。
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 150005;
int arr[N] = {0};
int vis[N] = {0};
inline bool cmp(int a, int b){
return a>b;
}
int main(){
int n;
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d",&arr[i]);
}
int sum = 0;
sort(arr, arr+n, cmp);
for(int i = 0; i < n; i++){
if(!vis[arr[i]+1]) vis[arr[i]+1] = 1,++sum;
else if(!vis[arr[i]]) vis[arr[i]] = 1, ++sum;
else if(arr[i]-1>0&&!vis[arr[i]-1]) vis[arr[i]-1] = 1, ++sum;
}
cout<<sum;
return 0;
}