19级暑假第七场训练赛

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\n");
        else
            printf("1\n");
    }
    else {
        if (c[sa % 3] == c[sb % 3])
            printf("0\n");
        else
            printf("1\n");
    }
}

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",n-ans);
    }
    return 0;
}

F:CodeForces - 1365D

采用的是记忆化搜索,唯一的技巧就是隔断的设置

\[if(mp[nr][nc]=='B'){vis[r][c]=-1;return;} \]

#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\n");
	else printf("Yes\n");
}
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\n",ans);
	}
	return 0;
}
posted @ 2020-08-21 20:36  Koshkaaa  阅读(181)  评论(1编辑  收藏  举报