2020校队第10次训练

B题

The girl Taylor has a beautiful calendar for the year y. In the calendar all days are given with their days of week: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.

The calendar is so beautiful that she wants to know what is the next year after y when the calendar will be exactly the same. Help Taylor to find that year.

Note that leap years has 366 days. The year is leap if it is divisible by 400 or it is divisible by 4, but not by 100 (https://en.wikipedia.org/wiki/Leap_year).

Input
The only line contains integer y (1000 ≤ y < 100’000) — the year of the calendar.

Output
Print the only integer y’ — the next year after y when the calendar will be the same. Note that you should find the first year after y with the same calendar.

Examples
Input
2016
Output
2044
Input
2000
Output
2028
Input
50501
Output
50507

题目大意:求下一个与y年所有日期(就是两年的周几和日期都是一一对应的)都一样的年份

思路:一开始就想到用两年间的日期间隔为7的倍数算。结果忘了和闰年相同的也应该是闰年,连样例都没过,就把闰年单独处理,结果完全跑偏。好在后来还是想起用一开始的思路,加上y于y’年的性质相同这一条件。

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
typedef long long ll;
#define scand(a) scanf("%lld", &a)
#define scandd(a,b) scanf("%lld%lld", &a, &b)
#define scanddd(a,b,c) scanf("%lld%lld%lld", &a, &b, &c)
const int maxn = 1e5 + 10;
using namespace std;
ll a[maxn];
ll n, m, p, q;

bool isrun(ll n)
{
	if((n % 4 == 0&&n % 100 != 0)||n % 400 == 0)
		return true;
	return false;
}

ll work(ll n)
{
	return n * 365 + n / 4 + n / 400 - n / 100;
}

int main()
{
	scand(n);
 	ll s = work(n);
	int i;
	for (i = n+1; i <= n + 200; i++)
	{
		if ((work(i) - s) % 7 == 0&&isrun(i) == isrun(n))
			break;
	}
	cout << i << endl;

	return 0;
}

D题

You are given an array a with n elements. Each element of a is either 0 or 1.

Let’s denote the length of the longest subsegment of consecutive elements in a, consisting of only numbers one, as f(a). You can change no more than k zeroes to ones to maximize f(a).

Input
The first line contains two integers n and k (1 ≤ n ≤ 3·105, 0 ≤ k ≤ n) — the number of elements in a and the parameter k.

The second line contains n integers ai (0 ≤ ai ≤ 1) — the elements of a.

Output
On the first line print a non-negative integer z — the maximal value of f(a) after no more than k changes of zeroes to ones.

On the second line print n integers aj — the elements of the array a after the changes.

If there are multiple answers, you can print any one of them.

Examples
Input
7 1
1 0 0 1 1 0 1
Output
4
1 0 0 1 1 1 1
Input
10 2
1 0 0 1 0 1 0 1 0 1
Output
5
1 0 0 1 1 1 1 1 0 1

题目大意:有k次把0变成1的机会,求变完后最长的连续1的个数并打印结果串,多个结果任意输出一组

思路:首先用前缀和数组存前i个0的数量,一层for循环迭代i作为最长串的终点,j作为起点,当sum0[i]-sum0[j]>k(k不足以填补这一串空缺的0)时更新答案并记下这个起点。输出时注意几种特殊情况即可。

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
typedef long long ll;
#define scand(a) scanf("%lld", &a)
#define scandd(a,b) scanf("%lld%lld", &a, &b)
#define scanddd(a,b,c) scanf("%lld%lld%lld", &a, &b, &c)
const int maxn = 3e5 + 10;
using namespace std;
ll a[maxn],sum1[maxn], sum0[maxn];
ll n, m, p, q;

int main()
{
	scandd(n,m);
	int j = 0;
	ll ans = 0;
	for(int i = 1; i <= n; i++)
	{
		scand(a[i]);
		if(a[i] == 1)
		{
			sum1[i] = sum1[i-1] + 1;//sum1好像没用到...
			sum0[i] = sum0[i-1];
		}
		else
		{
			sum0[i] = sum0[i-1] + 1;
			sum1[i] = sum1[i-1];
		}
		if(sum0[i]-sum0[j] > m)
			j++;
		if(i-j > ans)
		{
			p = j+1;
			ans = i-j;
		}
	}
//	cout<<"p = "<<p<<endl;
	if(m > sum0[n]||ans == n)
	{
		cout<<n<<"\n";
		for(int i = 1; i <= n; i++)
		{
			cout<<"1 ";
		}
	}
	else if(m == 0)
	{
		cout<<ans<<endl;
		for(int i = 1; i <= n; i++)
		{
			cout<<a[i]<<" ";
		}
	}
	else
	{
		cout<<ans<<endl;
		if(sum0[n] == n)
		{
			for(int i = 1; i <= ans; i++)
				cout<<"1 ";
			for(int i = ans+1; i <= n; i++)
			{
				cout<<a[i]<<" ";
			}
		}
		else
		{
			for(int i = 1; i < p; i++)
			{
				cout<<a[i]<<" ";
			}
			for(int i = p; i < p + ans; i++)
			{
				cout<<"1 ";
			}
			for(int i = p+ans; i <= n; i++)
			{
				cout<<a[i]<<" ";
			}
		}
	}
	return 0;
}

J题

Duff is in love with lovely numbers! A positive integer x is called lovely if and only if there is no such positive integer a > 1 such that a2 is a divisor of x.

Malek has a number store! In his store, he has only divisors of positive integer n (and he has all of them). As a birthday present, Malek wants to give her a lovely number from his store. He wants this number to be as big as possible.

Malek always had issues in math, so he asked for your help. Please tell him what is the biggest lovely number in his store.

Input
The first and only line of input contains one integer, n (1 ≤ n ≤ 1012).

Output
Print the answer in one line.

Examples
Input
10
Output
10
Input
12
Output
6
Note
In first sample case, there are numbers 1, 2, 5 and 10 in the shop. 10 isn’t divisible by any perfect square, so 10 is lovely.

In second sample case, there are numbers 1, 2, 3, 4, 6 and 12 in the shop. 12 is divisible by 4 = 22, so 12 is not lovely, while 6 is indeed lovely.

题目大意:给出一个数,求这个数及其所有因子中不能被a^2整除的数(a > 1)

思路:巨水题!!!一开始以为要先找出所有因子然后从大到小一一判断,结果毫无意外TLE了。后来发现若一个数n含有大于1的整数a的平方,这个整数a一定是素数或者其倍数,只要n还能整除某个素数的平方,就除以这个素数,直到不能除了就是答案。

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
typedef long long ll;
#define scand(a) scanf("%lld", &a)
#define scandd(a,b) scanf("%lld%lld", &a, &b)
#define scanddd(a,b,c) scanf("%lld%lld%lld", &a, &b, &c)
const ll maxn = 1e12 + 10;
using namespace std;
ll a[10000], p[2000010];
ll n, m,q, top, cnt;
bool pri[20000010];

void init()//埃氏筛,大概区间定一下素数平方能覆盖n(<= 1e12)
{
	for(ll i = 2; i <= 2000010; i++)
	{
		if(!pri[i])
		{
			p[cnt++] = i;
			//cout<<i<<" ";
			for(ll j = 2*i; j <= 20000010; j += i)
				pri[j] = 1;
		}
	}
}

int main()
{
	init();
	scand(n);
	if(n < 1000010&&!pri[n])//特判一下,记得限定n的取值,不然数组越界RE(不明不白RE两次)
		cout<<n<<endl;
	else 
	{
		for(ll j = 0; p[j]*p[j] <= n; j++)
			while(n % (p[j]*p[j]) == 0&&p[j] != 0)
				n/=p[j];
		cout<<n<<endl;
	}
	return 0;
}

总结一下,今天的状态比起之前几次还算不错(可能是题比较水),次次爆零真的太难受了…今后多刷点模板题和思路题拓展一下。
以下为补题:

G题

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: “abab”
The prefixes are: “a”, “ab”, “aba”, “abab”
For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.
Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.
Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.
Sample Input
1
4
abab
Sample Output
6
Sponsor

题目大意:给出一串长为n的字符串,要求统计所有前缀出现的总次数。例:abab中a出现2次,ab出现2次,aba出现1次,abab出现1次。

思路:一开始想着把所有前缀都拆下来然后用kmp找到每一串出现的次数,后来想想感觉会TLE就没写了。结果看了题解发现真的和kmp有点关系,算是next数组的拓展应用吧。next[ i ] 表示以s[ i ] 结尾的字符串前缀和后缀相等的最大长度为 next[ i ],从第i个向前递推next即为以s[ i ]结尾的前缀在i之前有多少个。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring> 
using namespace std;
const int mod = 10007;
int Next[200010];
char s[200010];
int n;

void get_next()
{
	int i = 0, j = -1;
	Next[0] = -1;
	while(i < n)//这里是从0开始的kmp算法,之前学的是从1开始的看到这个还不太习惯,以后改成从0开始
	{
		if(j == -1||s[i] == s[j])
		{
			i++;
			j++;
			Next[i] = j;
		}
		else
		{
			j = Next[j];
		}
	}
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		memset(Next,0,sizeof(Next));
		cin>>n;
		long long ans = n;
		scanf("%s", s);
		get_next();
		int j;
		for(int i = 1; i <= n; i++)
		{
			j = i;
			while(Next[j+1]>=1)//递推式
			{
				j = Next[j];
				ans = (ans+1)%mod;
			}
		}
		cout<<ans<<endl;
	}
	
	return 0;
 } 

A题

You are given a sequence of n integers a1, a2, . . . , an in non-decreasing order. In addition to that, you
are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the
most frequent value among the integers ai
, . . . , aj .
Input
The input consists of several test cases. Each test case starts with a line containing two integers n and
q (1 ≤ n, q ≤ 100000). The next line contains n integers a1, . . . , an (−100000 ≤ ai ≤ 100000, for each
i ∈ {1, …, n}) separated by spaces. You can assume that for each i ∈ {1, . . . , n − 1}: ai ≤ ai+1. The
following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which
indicate the boundary indices for the query.
The last test case is followed by a line containing a single ‘0’.
Output
For each query, print one line with one integer: The number of occurrences of the most frequent value
within the given range.
Note: A naive algorithm may not run in time!
Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
Sample Output
1
4
3

题目大意:给出n个数(非递减)和m个询问,求每个询问区间内出现次数最多的数的次数。

思路:一开始就想到用线段树或者ST表,但因为不知道如何将区间个数转化最值问题就没有写了。用num[i]记录i在位置时连续数字出现的个数即可,对于左区间连续数字被切断的特殊处理。

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#define scand(a) scanf("%d", &a)
using namespace std;
const int maxn = 100005; 
int a[maxn], num[maxn], st[maxn][25];

void rmq(int n)
{
	for(int i = 1; i <= n; i++)
		st[i][0] = num[i];
	for(int j = 1; j <= 20; j++)
		for(int i = 1; i + (1<<j)-1 <= n; i++)
			st[i][j] = max(st[i][j-1], st[i + (1<<(j-1))][j-1]);
}

int query(int l, int r)
{
	if(l == r)
		return 1;
	//int k = (int)log(r-l+1)/log(2);
	int k = 0;
	while(1<<(k+1) <= r-l+1)	k++;
	return max(st[l][k], st[r-(1<<k)+1][k]);
}


int main()
{
	int n, m;
	while(scand(n)&&n)
	{
		scand(m);
		for(int i = 1; i <= n; i++)
		{
			scand(a[i]);
			if(i == 1)
				num[i] = 1;
			else if(a[i] == a[i-1])
				num[i] = num[i-1]+1;
			else
				num[i] = 1;
		}
		rmq(n);
		while(m--)
		{
			int l, r;
			int ans = 0;
			scand(l);
			scand(r);
			int k = l;
			if(a[l] == a[r])
				ans = r-l+1;
			else
			{
				while(k <= r&&a[k] == a[k-1])
					k++;
				ans = max(k-l,query(k,r));
			}
			cout<<ans<<"\n";
		}
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值