A: CodeForces - 1300A
Input
1
1
1
Output
0
思路:
循环遍历输入,如果读入0,cnt++,sum++,如果这样sum == 0,cnt++即可
写的时候莫名写错,搞得WA2发
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
void solve() {
cin >> n;
int sum = 0;
int cnt = 0;
int tt;
for (int i = 1; i <= n; i++)
{
cin >> tt;
if (tt == 0)
cnt++, tt++;
sum += tt;
}
if (sum == 0) cnt++;
cout << cnt << endl;
}
int main() {
//freopen("in.txt", "r", stdin);
int t; cin >> t;
while (t--)solve();
}
B:ZOJ - 4107
题意:
给定一个序列,让你消除某个数,所得序列最高峰最少是多少
思路:
没做出来,解法摘自网络
例如样例 1 1 4 5 1 4 无论如何消除一个数,最后结果都是1,
但是样例 1 9 1 9 8 1 0 只要把第三个数 1 消除,得到1 9 9 8 1 0,就没有最高峰了答案为0。
实际上直接暴力就行了,首先求出原本有多少个峰,然后每次模拟消除一个数,看最多能消除多少个,最后拿原本的减去消除最多的就可以了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 99999999999;
const int maxn = 1e5 + 100;
ll a[maxn];
void solve() {
int n; cin >> n;
a[0] = a[n + 1] = inf;
for (int i = 1; i <= n; ++i)cin >> a[i];
ll sum = 0;//sum代表原序列中有多少个峰
for (int i = 2; i <= n - 1; i++)
if (a[i - 1] < a[i] && a[i + 1] < a[i])
sum++;
ll ansans = 0;
for (int i = 1; i <= n - 1; i++) {
ll ans = 0, ans1 = 0;
if (a[i - 1] > a[i + 1] && a[i - 1] > a[i - 2])//ans代表消除之后
ans++;
if (a[i + 1] > a[i - 1] && a[i + 1] > a[i + 2])
ans++;
if (a[i - 1] > a[i - 2] && a[i - 1] > a[i])//ans1代表消除之前
ans1++;
if (a[i + 1] > a[i + 2] && a[i + 1] > a[i])
ans1++;
if (a[i] > a[i - 1] && a[i] > a[i + 1])
ans1++;
ansans = max(ansans, ans1 - ans);//做差取最大
}
cout << sum - ansans << endl;
}
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)solve();
}
C:ZOJ - 4108
Sample Input
6
1 2
1 3
1 4
1 5
123456 12345678987654321
123 20190427201904272019042720190427
Sample Output
0
0
1
0
0
1
注释:这道题有规律,前12项如下(1代表奇数,0代表偶数)
下标n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Fn | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 |
Sn | 1 | 2 | 4 | 7 | 12 | 20 | 33 | 54 | 88 | 143 | 232 | 376 |
Sn奇偶性 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
由图中可以看出前n项斐波纳契数的和呈“1 0 0”的规律,3个一循环。
a,b的位数高达10000位,所以用char乐行输入,然后转化为整型。
有一个小知识:对于一个数,它的各个位数之和能够被3整除,那么这个数就是3的倍数。
让下标从0开始很巧妙,即能被3整除的下标对应的Sn是奇数,剩下的都是偶数。即各个位数之和对3取余为0则是“ 1 0 0”的第一个数1,取余为1是是“1 0 0”的中的第二个数0,取余为2是“1 0 0”中的第三个数0。
题目要求第a个和第b个之间斐波纳契数之和是奇数还是偶数,即求前b项和-前(a-1)项的和的奇偶性。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[10010], b[10010];
int c[3] = { 1,0,0 };
void solve() {
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
scanf("%s", a);
scanf("%s", b);
int aa = strlen(a);
int bb = strlen(b);
int sa = 0, sb = 0;
for (int i = 0; i < aa; i++) {
sa += a[i] - '0';
}
for (int i = 0; i < bb; i++) {
sb += b[i] - '0';
}
sa = sa - 2;//前a-1项和的奇偶
sb = sb - 1;//前b-1项和的奇偶
if (sa == -1) {
if (c[sb % 3] % 2 == 0)
printf("0
");
else
printf("1
");
}
else {
if (c[sa % 3] == c[sb % 3])
printf("0
");
else
printf("1
");
}
}
int main() {
//freopen("in.txt", "r", stdin);
//ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);//得注释掉,影响字符串读入
int t; cin >> t;
while (t--)solve();
}
D:CodeForces - 987C
样例输入1
5
2 4 5 4 10
40 30 20 10 40
样例输出1
90
样例输入2
3
100 101 100
2 4 5
样例输出2
-1
样例输入3
10
1 2 3 4 5 6 7 8 9 10
10 13 11 14 15 12 13 13 18 13
样例输出3
33
题目:要求$$i < j < k, a[ i ] < a[ j ] <a[ k ]; b[ i ] + b[ j ] + b[ k ]$$的最小值;
先求两个的和,再反向推出三个的和。。。算是用了两遍 (dp) 吧。。。
#include<bits/stdc++.h>
#define ms(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int maxn = 3e3 + 10;
const int inf = 0x3f3f3f3f;
ll a[maxn], b[maxn], val[maxn];
int n;
bool book[maxn];
void solve() {
ms(book, false); cin >> n;
for (int i = 1; i <= n; ++i)cin >> a[i];
for (int i = 1; i <= n; ++i)cin >> b[i];
for (int i = 1; i <= n; ++i) {
ll m = inf;
val[i] = b[i];
for (int j = i - 1; j > 0; --j)
if (a[i] > a[j])
m = min(m, b[j]);
if (m != inf)
book[i] = true, val[i] += m;
}
ll ans = 1 << 30;
for (int j = 1; j <= n; j++) {
if (!book[j]) continue;
for (int k = j + 1; k <= n; k++)
if (a[j] < a[k])
ans = min(ans, val[j] + b[k]);
}
if (ans == (1 << 30))cout << -1 << endl;
else cout << ans << endl;
}
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
solve();
}
E:ZOJ - 4104
题意:给定一个序列,每次可以把一个元素移到列首(最左边),求最少移几次使其有序(非降序)
(之前做过类似的题,可以把元素移到首或尾,思路相似)
思路:因为左移,可以肯定移动的都是较小值,若要保证操作次数最少,最大值一定不需要移动。
所以先排好序,确定之间的相对大小,然后找到最大值位置(因为有相同元素so从右往左找)
再从最大值往左找次大值,因为除最大值外,次大值就是当前最大值,所以同样不需要移动。
以此类推,直到找到最左边结束,我们找到的值都是不需要移动的,那么用总个数n减不需移动的个数 (ans) 即为需要移动的个数,解保证最小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100005],b[100005];
int main(){
int t,n,i,j;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int ma=0;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int ans=0;
for(i=n;i>=1;i--){
if(a[i]==b[n]){
int c=n;
for(j=i;j>=1;j--){
if(a[j]==b[c]){
c--;
ans++;
}
}
break;
}
}
printf("%d
",n-ans);
}
return 0;
}
F:CodeForces - 1365D
采用的是记忆化搜索,唯一的技巧就是隔断的设置
#include <stdio.h>
int n,m,vis[55][55],k[][2]={{-1,0},{1,0},{0,-1},{0,1}};//UP,DOWN,LEFT,RIGHT
char mp[55][55];
void dfs(int r,int c){
int nr,nc,i;
if(vis[r][c]!=0)return;
if(mp[r][c]=='#'||mp[r][c]=='B'){vis[r][c]=-1;return;}//遇到墙,遇到坏蛋
for(i=0;i<4;i++){
nr=r+k[i][0],nc=c+k[i][1];
if(1<=nr&&nr<=n&&1<=nc&&nc<=m)
if(mp[nr][nc]=='B'){vis[r][c]=-1;return;}//找坏蛋,设置墙,A cell that initially contains 'G' or 'B' cannot be blocked and can be travelled through.虽然有此句的限制,但是还是可以设置vis[r][c]=-1
}
vis[r][c]=1;//mp[r][c]=='G','.'
for(i=0;i<4;i++){
nr=r+k[i][0],nc=c+k[i][1];
if(1<=nr&&nr<=n&&1<=nc&&nc<=m)
if(!vis[nr][nc])dfs(nr,nc);//mp[nr][nc]=='G','.','#'
}
}
void solve(){
int i,j,flag=0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
vis[i][j]=0;
for(i=1;i<=n;i++)scanf("%s",mp[i]+1);
dfs(n,m);
for(i=1;i<=n;i++){
for(j=1;j<=m;j++)
if(mp[i][j]=='G'&&vis[i][j]!=1){flag=1;break;}//vis[i][j]==1,'G'没有被访问到;vis[i][j]==-1,或者为了挡住'B',不得不挡住'G'
if(flag)break;
}
if(flag)printf("No
");
else printf("Yes
");
}
int main(){
int t;
scanf("%d",&t);
while(t--)solve();
return 0;
}
G:CodeForces - 1352C
Input:
6
3 7
4 12
2 1000000000
7 97
1000000000 1000000000
2 1
Output:
10
15
1999999999
113
1000000001
1
3 7
(1,2,3,不能被3整除的数1,2),(4,5,6,不能被3整除的数4,5),
(7,8,9,不能被3整除的数7,8),(10,11,12,不能被3整除的数10,11)
周期是3,每个周期内不能被3整除的数有2个.故第7个数这样算7/2=3,3*3=9,9+7%2=9+1=10
输出10
4 12
(1,2,3,4,不能被4整除的数1,2,3),(5,6,7,8,不能被4整除的数5,6,7),
(9,10,11,12,不能被4整除的数9,10,11),(13,14,15,16不能被4整除的数13,14,15)
周期是4,每个周期内不能被4整除的数有3个.故第12个数这样算12/3=4,4*4=16,16-1=15
输出15
AC代码如下
#include <stdio.h>
#define LL long long
int main(){
int t;
LL n,k,c,ans;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&k);
c=n-1;//每n个数里,不能被n整除的数有n-1个
if(k%c==0)ans=n*(k/c)-1;
else ans=n*(k/c)+k%c;
printf("%lld
",ans);
}
return 0;
}