第二期2-3周周报

红色题目代表个人认为很难的题目。

第二周

第一题

   这题是真的难,以为需要用高精度来暴力模拟,但是事实上是用动态规划来做的,需要用二维数组dp[i][j]代表i操作j次的结果,当i不是9的时候只需要dp[i][j] = dp[i-1][j+1]就可以了。当i是9的时候那么就只能dp[i][j] = dp[1][j-1]+dp[0][j-1]了。最后再把每一位的位数相加就可以了。我看错题了还以为要找的是数值的大小,原来只需要找数值的长度。注意每一位都要取余操作。开long long。

#include <bits/stdc++.h>
#define int long long 
using namespace std;
const int MAXM = 2E5+30, mod = 1E9+7;
int t;
int m, ans;
char n[20];
int f[MAXM+5][10];		//i经过j次操作后变成f位数 
signed main() 
{
	for(int i = 0; i <= 9; ++i) 
	{
		f[0][i] = 1;
	}
	for(int i = 1; i <= MAXM; ++i)
	{
		for(int j = 0; j <= 8; ++j)
		{
			f[i][j] = f[i-1][j+1];
		}
		f[i][9] = (f[i-1][0]+f[i-1][1]) % mod;
	}
	scanf("%d", &t);
	while(t--)
	{
		ans = 0;
		scanf("%s %d", n, &m);
		int len = strlen(n);
		for(int i = 0; i < len; ++i)
		{
			ans = (ans+f[m][n[i]-'0']) % mod;
		}
		printf("%d\n", ans);
	}
	return 0;
}

第二题

    这一题就有亿点点的水了。只需要用set来存储每对点x1-x2,y1-y2的数值就好了,注意1->2和2->1是不一样的。记得对x1-x2,y1-y2进行约分,我们可以使用__gcd(x, y)函数求最大公约数,如果害怕gcd函数返回负值就对操作数取绝对值,这样就只能返回正值了。除以最大公约数就行。轻轻松松,简简单单

#include <bits/stdc++.h>
#define int long long
using namespace std;

int a[505], b[505];
int n;
set<pair<int, int> > s;		//总共需要多少种魔法 
signed main()
{
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		cin >> a[i] >> b[i];
	}
	for(int i = 1; i <= n; ++i) 
	{
		for(int j = 1; j <= n; ++j)
		{
			if(i != j)
			{
				int g = __gcd(abs(a[i]-a[j]), abs(b[i]-b[j]));//公约数
				s.insert(make_pair((a[i]-a[j])/g, (b[i]-b[j])/g));
			}
		}
	}
	cout << s.size() << endl; 
	return 0;
}

第三题

    怎么说,这题也是一道考数学的题,题目的意思不难理解,01/10和11可以互相转化,而00却不能被转化。首先,如果两个字符串长度不相等 那肯定是不行的,其次,如果长度相等,如果二者全等也可以。如果长度相等但是不全等,那么有一个为全0就是不能转化,否则就能转化。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n;
	cin >> n;
	while(n--)
	{
		string a, b;
		cin >> a >> b;
		if(a.length() != b.length()) 
		{
			cout << "NO" << endl;
		}
		else if(a == b)
		{
			cout << "YES" << endl;
		}
		else
		{
			int a1=0, b1=0;
			for(int i = 0; i < a.length(); ++i)
			{
				if(a[i] == '1')
				{
					++a1;
				}
				if(b[i] == '1')
				{
					++b1;
				}
			}
			if(a1 == 0 || b1 == 0)
			{
				cout << "NO" << endl;
			}
			else
			{
				cout << "YES" << endl;
			}
		}
	}
	return 0;
}

第四题

    这个题是一个前缀和的题,首先要定义前缀和数组,然后字符串中找到1就将前缀和+1,定义一个map,让map[sum[i]]++(map用来存放前缀和为n的情况的个数)。注意map[0]初始化为1 .做完这些准备工作后就可以ans+=map[i+k]*map[i],遍历所有可能存在的i直到map[i+k]为0。为什么这样做呢?因为我们要找到起始位置的可能情况和终点的可能情况(左开右闭开区间)但是考虑特殊情况当k=0时要找到所有连续为0的字串然后求每个字串长度n*(n-1)就行了。题目数据量大,开long long,注意初始化条件m[0] = 1不能放在执行步骤(循环)之后,否则会破坏执行结果。

#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int maxk = 1E6+6; 
int k;
string str; 
int sum[maxk];
signed main()
{
	cin >> k >> str;
	int len = str.length();
	str = '0'+str;		//这样就能1开始下表了
	if(k == 0) 
	{
		int ans = 0, now = 0;
		for(int i = 1; i <= len; ++i)
		{
			if(str[i] == '0')
			{
				now ++;
			}
			else
			{
				ans += now*(now+1)/2;
				now = 0;
			}
		}
		ans += now*(now+1)/2;		//记得最后一次的运算不要错 
		cout << ans << endl;
	}
	else
	{
		map<int, int> m;
		m[0] = 1;					//初始化条件
		for(int i = 1; i <= len; ++i)
		{
			sum[i] = sum[i-1]+str[i]-'0';
			m[sum[i]]++;
		}
		int n=0, ans = 0;
		while(m[n+k] != 0)
		{
			ans += m[n+k]*m[n];
			n++;
		}
		cout << ans << endl; 
	} 
	return 0;
}

第五题 

    知道什么是栈吗?嘿嘿,这题需要用到vector来模拟,最开始时一直push,找到第一个出栈的元素然后开始pop,如此循环往复找到下一个出栈的元素pop,如果已经push了所有的元素就一直pop就好了。输入输出量比较大,建议使用快读快写或者scanf和printf,把endl换成'\n'

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	vector<int> arr(n+1);
	for(int i = 1; i <= n; ++i)
	{
		cin >> arr[i];
	}
	int now = 1;
	for(int i = 1; i <= n; ++i)
	{
		while(now <= arr[i])
		{
			cout << "push " << now << endl;
			now++;
		}
		cout << "pop" << endl;
	}
	return 0; 
}

第六题

     这题就比较容易了,使用c++标准库函数,用vector暴力模拟,注意insert和erase需要用到迭代器。其他就没啥好说。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int m;
	vector<int> arr;
	cin >> m;
	while(m--)
	{
		string s;
		cin >> s;
		if(s == "insert")
		{
			int x, y;
			cin >> x >> y;
			arr.insert(arr.begin()+x, y);
		}
		else if(s == "query")
		{
			int k;
			cin >> k;
			cout << arr[k-1] << endl;
		}
		else if(s == "delete")
		{
			int x;
			cin >> x;
			arr.erase(arr.begin()+x-1);
		}
	}
	return 0;
}

第七题

    我咋也想不到的是我居然连水题都做了好几次才能过,复制粘贴的时候要注意代码的修改,循环程序设计要注意,别让自己想的和写的东西不一样。

#include <bits/stdc++.h>
using namespace std;
int n;
char vec[28][28];		//比较水的题
bool checkh()
{
	for(int i = 1; i <= n; ++i)
	{
		int cnt = 0, lian = 1;	//本行的计数和相连的计数。
		for(int j = 1; j <= n; ++j)
		{
			if(vec[i][j] == 'B')
			{
				cnt++;
			}
			if(j > 1 && vec[i][j] == vec[i][j-1])
			{
				lian++;
				if(lian >= 3)
				{
					return 0;
				}
			}
			else
			{
				lian = 1;
			}
		}
		if(cnt != n/2)
		{
			return 0;
		}
	}
	return 1;
}
bool checkl()
{
	for(int j = 1; j <= n; ++j)
	{
		int cnt = 0, lian = 1;	//本行的计数和相连的计数。
		for(int i = 1; i <= n; ++i)
		{
			if(vec[i][j] == 'B')
			{
				cnt++;
			}
			if(i > 1 && vec[i][j] == vec[i-1][j])
			{
				lian++;
				if(lian >= 3)
				{
					return 0;
				}
			}
			else
			{
				lian = 1;
			}
		}
		if(cnt != n/2)
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= n; ++j)
		{
			cin >> vec[i][j];
		}
	}
	if(checkh() && checkl())
	{
		cout << 1;
	}
	else
	{
		cout << 0;
	}
	return 0;
}

第八题

     这题就排一下序然后,再把每个元素和最小的元素求差,求所有差的最大公约数,如果是1就输出-1就可以了。

#include <bits/stdc++.h>
using namespace std;
int t, n;

int main()
{
	cin >> t;
	while(t--)
	{
		cin >> n;
		vector<int> arr(n+1);
		for(int i = 1; i <= n; ++i)
		{
			cin >> arr[i];
		}
		sort(arr.begin()+1, arr.end(), less<int>());	//从小到大排序
		int now=0, ans = arr[2]-arr[1];
		for(int i = 3; i <= n; i++)
		{
			now = arr[i]-arr[1];
			ans = __gcd(now, ans);						//找到最大公约数
		}
		if(ans == 0)
		{
			cout << -1 << endl;
		}
		else
		{
			cout << ans << endl;
		}
	}
	return 0;
}

第九题

    自己做的时候没思路,但是其实也没那么难,枚举删除26个字母的所有情况,然后对于这个序列存储为双端队列,进行模拟就可以了。

#include <bits/stdc++.h>
#define inf 0x7f7f7f7f
using namespace std;

int main()
{
	int t;
	cin >> t;
	while(t--)
	{
		int k;
		cin >> k;
		deque<char> d;		//双端队列
		while(k--)
		{
			char c;
			cin >> c;
			d.push_back(c);
		}
		int ans = inf;
		for(char c = 'a'; c <= 'z'; ++c)
		{
			int cnt = 0, now = 0;
			deque<char> t = d;		//建立缓存
			while(!t.empty())
			{
				if(t.front() == t.back())	//
				{
					t.pop_front();
					if(!t.empty())
					{
						t.pop_back();
					}
				}
				else if(t.front() == c)
				{
					t.pop_front();
					cnt++;
				}
				else if(t.back() == c)
				{
					t.pop_back();
					cnt++;
				}
				else
				{
					now = 1;
					break;
				}
			}
			if(!now)			//如果这种情况可行,那么要计数
			{
				ans = min(ans, cnt);
			}
		}
		if(ans != inf)
			cout << ans << endl;
		else
			cout << -1 << endl;
	}
	return 0;
}

第十题

前方高能预警!!!

    这题主要考察前缀积和动态规划,难度大,看题解我都看的很费劲。sum[i][j]指的是从第i项到第j项的积,记得每乘一项就要取余。然后再利用分治的思想划分数组(类比归并排序),从小到大枚举数组的长度,f[i][j]表示从i到j的子数组中的最大分数。可以利用三重循环枚举中间量,再次切割子数组,求子数组的乘积的分数值就可以了。

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
 
#define int long long
const int mod=1000003;
 
const int N=400;
int a[N],sum[N][N];
int f[N][N];
 
signed main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
 
    for(int i=1;i<=n;i++)
    {
        sum[i][i]=1;
        sum[i][i-1]=1;
        for(int j=i;j<=n;j++)
        {
            sum[i][j]=(sum[i][j-1]*a[j])%mod;
        }
    }
 
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            for(int k=i;k<j;k++)
            {
                f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+(sum[i][k]-sum[k+1][j])*(sum[i][k]-sum[k+1][j]));
            }
        }
    }
    cout<<f[1][n]<<endl;
    return 0;
}

第三周

第一题

    还是考数学的题,只要找到最大公约数,再看每一个数除了最大公约数,1,2和3以外有没有其他的约数,如果还有的话就做不到了。如果没有就OK

#include <bits/stdc++.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int t, n;
const int maxn = 2E5+5;
int arr[maxn];
int main() 
{
	cin >> t;
	while(t--)
	{
		cin >> n;
		int g;
		for(int i = 1; i <= n; ++i)
		{
			cin >> arr[i];
			if(i == 1)
			{
				g = arr[i];
			}
			else
			{
				g = __gcd(arr[i], g);	//找到所有数字的最大公约数 
			}
		}
		int tmp, lef = 0, ans = 1; 
		for(int i = 1; i <= n; ++i) 
		{
			tmp = arr[i] / g;			//直接用arr来存放每个数 
			while(1)
			{
				lef = tmp % 2;
				if(lef != 0)
				{
					break;
				} 
				tmp /= 2;
			}
			lef = 0;
			while(1)
			{
				lef = tmp % 3;
				if(lef != 0)
				{
					break;
				}
				tmp /= 3; 
			}
			if(tmp != 1)
			{
				ans = 0;
			}
		}
		cout << (ans? "YES":"NO") << endl;
	}
	return 0;
}

第二题

这是本周唯一一个相对难一点的题

    先上ac code,看上去不很难啊???

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1E6+6;
char str[maxn];			//默认全0
int last[26], sum;		
signed main()
{
	cin >> str;
	int len = strlen(str);
	memset(last, -1, sizeof(last));	//置为-1
	for(int i = 0; i < len; ++i)
	{
		sum += (len-i)*(i-last[str[i]-'a']);
		last[str[i]-'a'] = i;
	}
	cout << sum;
	return 0;
}

     事实上,这题不适合用前缀和,因为不满足字串分值和的条件,但是枚举26个字母的出现次数又太过麻烦。代码中使用last[i]来标记上一个字母出现的位置。因为字符串下表从0开始所以为了区分是否在初始位置,把last初始化为-1。(len-i)*(i-last[str[i]-'a'])时啥意思呢?当前字串的最大长度乘以当前位置和上一个位置的距离。因为从last[str[i]-'a']+1的位置开始,i位置所在的字母+1的buff才生效,而这个+1的buff对这个位置开始的所有能够碰到i的字串都生效。害,这种感觉就是只可意会不可言传啊!附图 

第三题

     主要考察对内置数据结构set和map的运用,能用map<int, int>就不要用set<pair<int,int> >了。map对于数对还是比set要好用的。

#include <bits/stdc++.h>
using namespace std;
map<int, int> m1, m2;
int n, op, sum;

int main()
{
	cin >> n;
	while(n--)
	{
		cin >> op;
		if(op == 1)
		{
			int w, t;
			cin >> w >> t;
			if(m1.count(w) == 0 && m2.count(t) == 0)
			{
				m1[w] = t;
				m2[t] = w;
			}
		}
		else if(op == 2)
		{
			int f = m1.begin()->first, s = m1.begin()->second;
			m1.erase(f);
			m2.erase(s);
		}
		else
		{
			int f = m2.begin()->first, s = m2.begin()->second;
			m1.erase(s);
			m2.erase(f);
		}
	}
	for(auto x:m1)
	{
		sum += x.first;
	}
	cout << sum;
	return 0;
}

第四题

    水题, 只要排好序然后从后往前找差距就可以了,如果一个差距大于k那么前面的都不可能胜利。可以反向排序这样子就更容易些

#include <bits/stdc++.h>
using namespace std;
int n, k, sum=1;

int main()
{
	cin >> n >> k;
	vector<int> arr(n);
	for(int i = 0; i < n; ++i)
	{
		cin >> arr[i];
	}
	sort(arr.begin(), arr.end(), less<int>());
	for(int i = n-1; i > 0; --i)
	{
		if(arr[i]-arr[i-1] <= k)
		{
			sum++;
		}
		else
		{
			break;
		}
	}
	cout << sum << endl;
	return 0;
}

第五题

    水题*2,真以为我格某不会next_permutation?不过小心输入输出超时!如果想用cin,cout输出的话,快读快写代码如下:

#define endl '\n'
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n, num;
	cin >> n;
	vector<int> arr;
	for(int i = 1; i <= n; ++i)
	{
		cin >> num;
		while(num--)
		{
			arr.push_back(i);
		}
	}
	do
	{
		bool flag = 0;
		for(int x: arr)
		{
			if(!flag)
			{
				printf("%d", x);
				flag = 1;
			}
			else
			{
				printf(" %d", x);
			}
		}
		printf("\n");
	}
	while(next_permutation(arr.begin(), arr.end()));
	return 0;
}

第六题

     水题*3,真以为格某人是面团捏的吗?

#include <bits/stdc++.h>
#define int long long
using namespace std;
int sum;
int n, m, t;
string x;
int chtonum(char c)
{
	if(isdigit(c))
	{
		return c-'0';
	}
	else if(isupper(c))
	{
		return c-'A'+10;
	}
	else if(islower(c))
	{
		return c-'a'+36;
	}
}
char inttoch(int i)
{
	if(i < 10)
	{
		return i+'0';
	}
	else if(i < 36)
	{
		return i-10+'A';
	}
	else
	{
		return i-36+'a';
	}
}
signed main()
{
	cin >> n >> m;
	while(n--)
	{
		int num = 0;
		cin >> t >> x;	//一个t进制数x
		while(!x.empty())
		{
			num = num*t+chtonum(x[0]);
			x.erase(x.begin());
		}
		sum += num;
	}
	stack<char> s;
	while(sum > 0)
	{
		s.push(inttoch(sum%m));
		sum /= m;
	}
	while(!s.empty())
	{
		cout << s.top();
		s.pop();
	}
	return 0;
}

第七题

    水题*4,只需要判断字符串“循环移位”后能不能等于自己就行了。字串的长度可以等于自己的啊

#include <bits/stdc++.h>
using namespace std;
int t;
int main()
{
	cin >> t;
	while(t--)
	{
		int n;
		string str, str1;
		cin >> n >> str;
		str1 = str;
		reverse(str1.begin(), str1.end());
		bool flag = 0;
		while(n--)
		{
			char c = str.back();
			str.pop_back();
			str = c + str;
			if(str == str1)
			{
				flag = 1;
				break;
			}
		}
		if(flag)
		{
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO" << endl;
		}
	}
	return 0;
}

第八题 

    水题*5,在格某人面前还有哪道题是无尽?主要是判断集合的从属关系,题目的数据量比较小,暴力枚举就可以。

#include <bits/stdc++.h>
using namespace std;
set<int> s[102];	//set集合
bool f[102];
int main()
{
	int t;
	cin >> t;
	for(int i = 1; i <= t; ++i)
	{
		int n;
		cin >> n;
		int num;
		while(n--)
		{
			cin >> num;
			s[i].insert(num);		//集合中加入元素
		}
	}
	for(int i = 1; i <= t; ++i)		//对于i集合,要找j集合是否为其子集
	{
		for(int j = 1; j <= t; ++j)
		{
			if(j != i && s[j].size() <= s[i].size())
			{
				bool flag = 1;			//s[j]是否为s[i]的子集
				for(auto x: s[j])
				{
					if(s[i].count(x) == 0)	//如果有一个没找到就说明不是子集
					{
						flag = 0;
					}
				}
				if(flag)
				{
					f[i] = 1;
				}
			}
		}
	}
	for(int i = 1; i <= t; ++i)
	{
		if(f[i])
		{
			cout << "NO" << endl;
		}
		else
		{
			cout << "YES" << endl;
		}
	}
	return 0;
}

第九题

    emmm,我调了两次没对,就不说是水题了。full的条件是两个都是素数且不相等,partial credit的条件是两个数互质且都是完全平方伪素数,光互质不行,因为有一个数可能自身含有完全平方因子。

#include <bits/stdc++.h>
#define int long long
using namespace std;
bool isprim(int a)
{
	int t = sqrt(a);
	for(int i = 2; i <= t; ++i)
	{
		if(a % i == 0)
		{
			return false;
		}
	}
	return true;
}
bool isff(int a)	//是不是ff质数
{
	int t = sqrt(a);
	for(int i = 2; i*i <= a; ++i)
	{
		if(a % (i*i) == 0)
		{
			return false;
		}
	}
	return true;
}
signed main()
{
	int a, b;
	cin >> a >> b;
	bool fa = isprim(a), fb = isprim(b);
	if(fa && fb && a != b)
	{
		cout << "full credit" << endl;
	}
	else
	{
		bool ffa = isff(a), ffb = isff(b);
		if(ffa && ffb && __gcd(a, b) == 1)
		{
			cout << "partial credit" << endl;
		}
		else
		{
			cout << "no credit" << endl;
		}
	}
	return 0;
}

第十题

    本周的boss,我看了一次题解,但是也不算太难。由于题目中的数组是从后往前操作的,因此反向存数组比较好,一次最多可以拷贝前面的所有元素。从第一个开始,找第二个如果和第一个元素相等就加入“等值区块”,否则就把前面的“等值集合”拷贝,并覆盖后面的所有数。每次集合成指数增大。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		vector<int> arr(n);		//从后往前操作的数组,可以用反向存数组
		for(int i = n-1; i >= 0; --i)
		{
			cin >> arr[i];
		}
		int now = 1, ans = 0;
		while(now < n)
		{
			if(arr[now] == arr[0])
			{
				++now;
			}
			else
			{
				now *= 2;
				ans++;
			}
		}
		cout << ans << '\n';
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值