题目
A、Polycarp and Coins
题目链接:Polycarp and Coins
题意:你有两种硬币:一种是面值为一元的、另一种是面值为二元的,现在给出一个数值,要求由尽可能数量相同两种硬币组成这个值,输出一元硬币和二元硬币的数量。
思路:首先清楚两个硬币组合是为3,对于所有数值是3的倍数的话,都可以取到相等的,如果对3取模为1就加一个一元硬币,取模为二就加一个二元硬币,两者的基础值都是数值除3。
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <math.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a = b; a <= c; a ++)
#define drep(a, b, c) for(int a = b; a >= c; a --)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
#define ccn cout << '\n'
const double PI = acos(-1.0);
const double eps = 1e-6;
ll qpow(ll a, ll b){
ll res = 1; while(b){if(b&1)res*=a; a*=a;b>>=1;} return res;
}
inline int read(){
int s=0,w=1; char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main ()
{
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
int a = n/3;
int b = n - 2*a;
while(b - a >= 2)
{
b -= 2;
a++;
}
cout << b << " " << a << endl;
}
return 0;
}
B1、Wonderful Coloring - 1
题意:涂色题,要么涂红色或者绿色还是不涂三种选择,要求满足字符串中每种字母不会被两种颜色同时涂到,而且涂红色的次数应该和绿色想等,
求红色最多涂了多少。
思路:很简单的题,数据范围也很小,首先是设置一个数组,统计每种字母出现的次数,然后遍历这个数组,如果次数大于等于2:ans直接加一,如果次数小于2:则left加一。最后ans加上left/2的值就是答案了。
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <math.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a = b; a <= c; a ++)
#define drep(a, b, c) for(int a = b; a >= c; a --)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
#define ccn cout << '\n'
const double PI = acos(-1.0);
const double eps = 1e-6;
ll qpow(ll a, ll b){
ll res = 1; while(b){if(b&1)res*=a; a*=a;b>>=1;} return res;
}
inline int read(){
int s=0,w=1; char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int ch[28], t;
int main ()
{
cin >> t;
while(t--)
{
for(int i = 1; i <= 26; i++)
{
ch[i] = 0;
}
string s;
cin >> s;
for(int i = 0; i < s.size(); i++)
{
ch[s[i]-'a'+1] ++;
}
int left = 0, ans = 0;
for(int i = 1; i <= 26; i++)
{
if (ch[i] >= 2)
{
ans ++;
}
if (ch[i] == 1)
{
left ++;
}
}
// cout << left << " " << ans << enld;
ans += left/2;
cout << ans << endl;
}
return 0;
}
B2、 Wonderful Coloring - 2
题意:是上一题的增加版本,输入一个n个元素的数组和k种颜色,尽量给数组涂色,满足以下要求:可以涂k种颜色种的任意一种也可以不涂、每种颜色使用的数量必须相等、一个数不允许被同一种颜料涂两次、尽量给数组涂上最多种的颜色。
思路:我们可以简单的想到,如果这个数出现的次数大于等于k的时候,所有这个数就直接涂1到k剩下的都是零。对于剩下的数,我们依次涂1-k就可以了,只不过注意在最后可能会剩下来一些地方情况,即剩下的数不够涂k次,导致最后每种颜色涂的次数不相等,这里我卡住了一个地方,那就是可能会给一个色涂上了一个重复的颜色,所以我们这里可以用一个结构体排序的方式来进行处理。
吐槽:这个题真的是,没注意到直接过去会重复涂,中间实现的时候自闭了,以为自己码不出来已经有思路的题,结果是思路出错了,真的无语。
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <math.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a = b; a <= c; a ++)
#define drep(a, b, c) for(int a = b; a >= c; a --)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
#define ccn cout << '\n'
const double PI = acos(-1.0);
const double eps = 1e-6;
ll qpow(ll a, ll b){
ll res = 1; while(b){if(b&1)res*=a; a*=a;b>>=1;} return res;
}
inline int read(){
int s=0,w=1; char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int t, a[200005], b[200005], c[200005], ans[200005], n, k;
struct node
{
int val, pos, ans;
};
node x[200005];
bool cmp1(node p, node q)
{
return p.val < q.val;
}
bool cmp2(node p, node q)
{
return p.pos < q.pos;
}
int main ()
{
cin >> t;
while(t--)
{
cin >> n >> k;
for(int i = 1; i <= n; i ++)
{
cin >> x[i].val;
x[i].pos = i;
b[x[i].val]++;
}
int sum = 0;
for(int i = 1;i <= n; i++)
{
if (b[x[i].val] < k) sum ++;
}
sort(x+1, x+1+n, cmp1);
int top = sum/k*k, num = 1, mark = 1;
int flag = 1;
for(int i = 1; i <= n; i ++)
{
if (b[x[i].val] >= k)
{
x[i].ans = ++c[x[i].val];
if (x[i].ans > k) x[i].ans = 0;
}
else
{
if (num <= top)
{
num++;
x[i].ans = mark ++;
if (mark > k) mark = 1;
}
}
}
sort(x+1, x+1+n, cmp2);
// ==== ==== ==== ==== ==== ====
for(int i = 1; i<= n; i++)
{
cout << x[i].ans << " ";
}
cout << endl;
for(int i = 1; i <= n; i++)
{
c[x[i].val] = 0;
b[x[i].val] = 0;
x[i].ans = 0;
}
}
return 0;
}
C、C - Interesting Story
题目链接:Interesting Story
题意:有t组测试样例,每组有n个单词,所有单词都只由a、b、c、d和e一共
五种字母构成,对于一个单词,如果有一种字母总数比除它以外所有字母数的大,那么对于这个单词来讲就是符合要求的,同样的对于构成这样的一个文章也是如此,求一个文章最多由多少个单词构成且符合要求。
思路:我也是思考好一会,最后看了下别人的题解,恍然大悟,这个题不难。首先我们可以注意到,对于文章来讲不一定要其中的每一个单词都满足要求,我们只对总体要求满足就可以,那么我们肯定选取最大满足的单个单词,也是需要排序一下,我们思考一下复杂度,因为只有五种字母而且所有单词的总长度不大于2e5,所以我们直接枚举五种字母分别猜想为最大的结果,最后取结果中最大的即可,不会TLE。
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <math.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a = b; a <= c; a ++)
#define drep(a, b, c) for(int a = b; a >= c; a --)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
#define ccn cout << '\n'
const double PI = acos(-1.0);
const double eps = 1e-6;
ll qpow(ll a, ll b){
ll res = 1; while(b){if(b&1)res*=a; a*=a;b>>=1;} return res;
}
inline int read(){
int s=0,w=1; char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int N = 200005;
int a[N], b[N], c[N], d[N], e[N], n, t;
string s[N];
bool cmp(int a, int b)
{
return a > b;
}
int main ()
{
cin >> t;
while(t--)
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> s[i];
int aa = 0, bb= 0, cc = 0, dd = 0, ee = 0;
for(int j = 0; j < s[i].size(); j++)
{
if (s[i][j] == 'a') aa++;
if (s[i][j] == 'b') bb++;
if (s[i][j] == 'c') cc++;
if (s[i][j] == 'd') dd++;
if (s[i][j] == 'e') ee++;
}
a[i] = 2*aa - s[i].size();
b[i] = 2*bb - s[i].size();
c[i] = 2*cc - s[i].size();
d[i] = 2*dd - s[i].size();
e[i] = 2*ee - s[i].size();
}
sort(a+1, a+1+n, cmp);
sort(b+1, b+1+n, cmp);
sort(c+1, c+1+n, cmp);
sort(d+1, d+1+n, cmp);
sort(e+1, e+1+n, cmp);
int sum = 0, ans=0;
for(int i = 1; i <= n; i++)
{
sum += a[i];
if (sum > 0) ans=max(ans, i);
}
sum = 0;
// cout << ans << endl;
//====
for(int i = 1; i <= n; i++)
{
sum += b[i];
if (sum > 0) ans=max(ans, i);
}
sum = 0;
// cout << ans << endl;
//====
for(int i = 1; i <= n; i++)
{
sum += c[i];
if (sum > 0) ans=max(ans, i);
}
sum = 0;
// cout << ans << endl;
//====
for(int i = 1; i <= n; i++)
{
sum += d[i];
if (sum > 0) ans=max(ans, i);
}
sum = 0;
// cout << ans << endl;
//====
for(int i = 1; i <= n; i++)
{
sum += e[i];
if (sum > 0) ans=max(ans, i);
}
//====
// cout << "ans = ";
cout << ans << endl;
}
return 0;
}
D1 Domino (easy version)
题目链接:Domino(easy version)
题意:有一个n乘以m的空间,空间为偶数,多米诺骨牌是一个面积为1乘以2的矩形,在这个空间里面有两种表示方法,一种是竖着、一种方式横着,题目要求能不能刚好k个横着,剩下都必须竖着,而且必须占满所有的空间。
思路:首先,我们从空间数是偶数开始,我可以发现宽和高不可以都是奇数,至少有一个或者两个都是偶数。然后我们再设想当高不为奇数的时候,无论宽度是奇数还是偶数都可以用竖着的骨牌填满,同理如果是高度是奇数,那么宽度一定是偶数,那么刚好可以用一排横着的先填满,这个情况可以看做是优先填满然后再优先竖着的。最后我们知道两个竖着的换成两个横着的,不过这里要注意一个小点,就是必须是横着连续的两个竖着的。最后这个题没有什么需要码力的地方,只要按照思路判断条件就可以了。
吐槽:不知道为什么放在D1,我觉得可以放在B2前面哇。
#include <bits/stdc++.h>
using namespace std;
int main ()
{
int n, m, k, t;
cin >> t;
while(t--)
{
cin >> n >> m >> k;
int x = (n/2)*(m/2);
int h = 0;
if (n%2 == 1)
{
h += m/2;
}
if (k == h || ((k-h)%2==0 && (k-h)/2 <= x) && k>= h)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}
D2、Domino (hard version)
题意:看过D1了吗,就是要求把多米诺骨牌打出来,为了表示不相同的多米诺骨牌,就是一个多米诺骨牌用两个连续的小写字母表示,然后相邻的骨牌肯定不能用同一种小写字母表示(废话 )。
思路:由之前可以知道最多只会有一个边会是奇数,如果有这个奇数边,我们先可以用e和f来单独处理这一个边,然后剩下部分就是一个偶数矩阵,我是选择用c和d交叉表示竖着的骨诺牌,最后根据需要的从左上角开始处理生成横着的多米诺骨牌,这样就可以好处理很多。
吐槽:这居然是cf的2100分题,太顶了吧,前面D1也是,太那啥玄学了,我还小心翼翼的处理每个情况。结果一不小心就写太多了,来贴贴代码了。(重复部分请无视哇 )
#include <bits/stdc++.h>
using namespace std;
char a[105][105];
void output(int n, int m)
{
for(int i = 1; i <= n; i++)
{
// cout << i << " : " ;
for(int j = 1; j <= m; j++)
{
cout << a[i][j];
}
cout << endl;
}
}
int main ()
{
int n, m, k, t;
cin >> t;
while(t--)
{
cin >> n >> m >> k;
int x = (n/2)*(m/2);
int h = 0;
if (n%2 == 1)
{
h += m/2;
}
if (k == h || ((k-h)%2==0 && (k-h)/2 <= x) && k>= h)
{
cout << "YES" << endl;
if (n%2 == 1 && m%2==0)
{
// ==== ==== ==== ==== ====
for(int i = 1; i <= m; i+=2)
{
if((i+1)/2%2 == 1) a[n][i] = a[n][i+1] = 'e';
else a[n][i] = a[n][i+1] = 'f';
}
for(int i = 1; i <= n-1; i+=2)
{
for(int j = 1; j <= m; j++)
{
if ( (i+1)/2%2==1 )
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'c';
}
else
{
a[i][j] = a[i+1][j] = 'd';
}
}
else
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'd';
}
else
{
a[i][j] = a[i+1][j] = 'c';
}
}
}
}
// ==== ==== ==== ==== ====
int y = (k - h)/2, cnt = 0;
// cout << "y : "<< y << endl;
for(int i = 1; i <= n-1; i +=2)
{
if(cnt >= y) break;
for(int j = 1; j <= m; j += 2)
{
if(cnt >= y) break;
if( (j+1)/2%2 == 1)
{
a[i][j] = a[i][j+1] = 'a';
a[i+1][j] = a[i+1][j+1] = 'b';
cnt++;
}
else
{
a[i][j] = a[i][j+1] = 'b';
a[i+1][j] = a[i+1][j+1] = 'a';
cnt++;
}
}
}
// ==== ==== ==== ==== ====
}
else if (n%2==0 && m%2==1)
{
//---------------------------------------------------------------
for(int i = 1; i <= n; i+=2)
{
if((i+1)/2%2 == 1) a[i][m] = a[i+1][m] = 'e';
else a[i][m] = a[i+1][m] = 'f';
}
// ==== ==== ==== ====
for(int i = 1; i <= n; i+=2)
{
for(int j = 1; j <= m-1; j++)
{
if ( (i+1)/2%2==1 )
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'c';
}
else
{
a[i][j] = a[i+1][j] = 'd';
}
}
else
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'd';
}
else
{
a[i][j] = a[i+1][j] = 'c';
}
}
}
}
// ==== ==== ==== ==== ====
int y = (k - h)/2, cnt = 0;
// cout << "y : "<< y << endl;
for(int i = 1; i <= n; i +=2)
{
if(cnt >= y) break;
for(int j = 1; j <= m-1; j += 2)
{
if(cnt >= y) break;
if( (j+1)/2%2 == 1)
{
a[i][j] = a[i][j+1] = 'a';
a[i+1][j] = a[i+1][j+1] = 'b';
cnt++;
}
else
{
a[i][j] = a[i][j+1] = 'b';
a[i+1][j] = a[i+1][j+1] = 'a';
cnt++;
}
}
}
}
else if (n%2 == 0 && m%2== 0)
{
for(int i = 1; i <= n; i+=2)
{
for(int j = 1; j <= m; j++)
{
if ( (i+1)/2%2==1 )
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'c';
}
else
{
a[i][j] = a[i+1][j] = 'd';
}
}
else
{
if (j%2 == 1)
{
a[i][j] = a[i+1][j] = 'd';
}
else
{
a[i][j] = a[i+1][j] = 'c';
}
}
}
}
// ==== ==== ==== ==== ====
int y = (k - h)/2, cnt = 0;
// cout << "y : "<< y << endl;
for(int i = 1; i <= n; i +=2)
{
if(cnt >= y) break;
for(int j = 1; j <= m; j += 2)
{
if(cnt >= y) break;
if( (j+1)/2%2 == 1)
{
a[i][j] = a[i][j+1] = 'a';
a[i+1][j] = a[i+1][j+1] = 'b';
cnt++;
}
else
{
a[i][j] = a[i][j+1] = 'b';
a[i+1][j] = a[i+1][j+1] = 'a';
cnt++;
}
}
}
}
output(n, m);
}
else
{
cout << "NO" << endl;
}
}
return 0;
}