下午有事去了趟医院,只能把红酒哥那边比赛的签到题写完了。现在又没补题又没题解的,两道没法做是真难受
codeforce 1551 B2 题目链接:点击这里传送
题意:给出n个元素以及他们的编号,还有颜料的种类个数,要求你尽可能多的给他们上色
1. 同一编号的元素不能涂有相同的颜色
2. 每种颜色的数量必须一样多(未上色的不算)
3. 颜色的种类不能超出给定的个数
思路:
构造一个结构体,记录他们的颜色,编号及种类(自己定义)
首先统计每个种类的数量,对于小于等于k的,他们的种类就是颜色的编号,对于大于k的他们的种类就是0即不上色。然后依据整个数组的原始编号进行排序。
过后将n%k,也就是不能被k整除的部分的元素颜色赋为0。接下来每k次一个周期对元素进行染色,由于之前的操作已经确保不会出现重复颜色和有剩余这两种情况出现,最后构造出来的一定是合法的。
最后根据原始编号排序并输出他们的颜色
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
int t,n,k;
struct node{
int id;//编号
int val;//种类
int color;//颜色
}a[MAXN];
bool cmp1(node a,node b){return a.val<b.val;}
bool cmp2(node a,node b){return a.id<b.id;}//复位
int color[MAXN];
map <int ,int >mp;
//构造一个结构体,以储存每个方块的颜色,起始顺序,种类。
//首先统计每个种类的数量,将其中数量大于k的方块多出的个数的种类变为0,再将整个数组按照方块的编号进行排序
//再将不能被整除的余数个方块的编号变为0,遍历数组,将编号为0的方块不上色(= 0)
//之后每k次一个周期对方块上色,最后按方块的初始顺序重新排序并输出。
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
mp.clear();
cin>>n>>k;//颜色的种类
int N=n;int temp=0;
for(int i=1;i<=n;i++)
{
cin>>a[i].val;
a[i].id=i;
mp[a[i].val]++;
if(mp[a[i].val]>k) //同一种类的太多了,一定不能上色了
{
a[i].val=0;
N--;
}
}
temp=N%k;//实际能上色的数量还要%一下k
sort(a+1,a+1+n,cmp1);
int cnt=1;
for(int i=1;i<=n;i++)
{
if(a[i].val==0) a[i].color=0;//之前标记的不能上色的方块
else if(temp>0)//余数还有多
{
a[i].color=0;
temp--;
}
else //每k次一个周期进行上色,因为之前把种类过多的情况处理了,所以肯定能保证合法
{
a[i].color=cnt;
cnt++;
if(cnt>k) cnt=1;
}
}
sort(a+1,a+1+n,cmp2);
for(int i=1;i<=n;i++) cout<<a[i].color<<" ";
cout<<endl;
}
return 0;
}
红酒哥比赛的K题
题意:
给出n和一串字符串,这串字符串是1到n的递增排列,但是其中少了一个数,要求你把少的数找出来。
思路:
对于中途出现了非法的情况写法还是很多的,可以直接找,也可以截子串和提前打好的表进行比对。但是如果少的是n就意味着这个字符串是合法的(至少程序认为是),就不会输出任何数。这个特判当时写的时候没想到,被卡了三发,可惜。
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int a[105];
string ans[105];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int cnt = 1;
int step = 1;
int pos = 1;
cin >> n;
cin >> s;
for (int i = 1; i <= 100; i++)
{
ans[i] = to_string(i);
}
for (int i = 0; i < s.length(); i += pos)
{
string temp = s.substr(i, step);
if (temp != ans[cnt])
{
cout << cnt;
return 0;
}
cnt++;
if (cnt == 10) step = 2;
if (cnt == 11) pos = 2;
if (cnt == 100) step = 3;
if (cnt == 101) pos = 3;
}
cout << n;
return 0;
}
红酒哥比赛的M题
题意:
一共有n个评委,他们最高能打3分,最低能打-3分,现已给出m个评委的成绩,让你求现阶段可能的最高分和最低分
思路:
懒得逼逼
#include<bits/stdc++.h>
using namespace std;
double n, m;
double a[105];
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
double max_val = n * 3-0.0;
double min_val = n * (-3)-0.0;
for (int i = 1; i <= m; i++)
{
double temp;
cin >> temp;
temp /= 1.0;
max_val = max_val - (3 - temp);
min_val = min_val + (temp + 3);
}
printf("%lf %lf", min_val / n + 0.0, max_val / n + 0.0);
return 0;
}
红酒哥比赛的P题
这题还是挺有意思的,赛时看到了n的范围一时有点头大,后来看到了买数据范围突然转过弯来发现一个map容器就行了。
题意:
一个组有n个组员,某一天这些组员会发m条消息。这些组员都是不看消息的懒狗,只在自己发消息的时候会把未读消息清空(包括自己发的)。输入m行,内容是发消息的组员的编号,输出m行,要求你求出某个组员发出消息后整个组内所有人的未读消息数量。
思路:
定义一个map容器,里面存放的内容是这名编号的成员最近一次操作的轮数。这样就可以在他发完消息前把他的未读消息清空。具体操作就是 sum-=cnt-mp[i]。在他发出消息后sum在累加n-1就行。
#include<bits/stdc++.h>
using namespace std;
int n, m;
long long sum = 0;
map <int, int> mp;//某个数最后一次清空操作在第几回合
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
int cnt = 0;
while (m--)
{
int pos;
cin >> pos;
sum = sum - (cnt - mp[pos]);
cnt++;
mp[pos] = cnt;
sum = sum + n-1;
cout << sum<<endl;
}
return 0;
}
红酒哥的J题
题意:
给你一个字符串,你可以选择将两个任意字符交换,也可以不换,这叫一次操作。现根据给出的字符串,若一个人背着你做出了一次操作,你是否一定能察觉
思路:
判断字符串有没有重复字符
#include<bits/stdc++.h>
using namespace std;
string s;
set <char> ss;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> s;
for (int i = 0; i < s.length(); i++)
{
ss.insert(s[i]);
}
if (ss.size() == s.length()) cout << 1;
else cout << 0;
return 0;
}
Codeforces 1551A 题目链接
题意:
任意选定一个区间,定义f(l,r)是区间内的最大值乘区间内的最小值的结果,输出这个结果的最大值。
思路:
先说结论,就是一轮遍历下来 a[i]乘a[i-1]的最大值 。
假设先任意选取一对相邻的数,如果我们添加一个附近的数能改变f(i,j)的值,那么实际上这个值就是f(i-1,i)的值或者f(j,j+1)的值或者还要更大。也就是说看起来之前f(i,j)的值会更新,但实际上只是另一对相邻(i,j)的值。
#include<bits/stdc++.h>
using namespace std;
int t, n;
#define MAXN 100005
long long a[MAXN];
long long ans;
int pos;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
ans = 0;
cin >> n;
memset(a, 0, sizeof(a));
long long max_n=-1;
long long min_n=-1;
long long ans = 0;
pos = 1;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (i > 1) ans = max(a[i] * a[i - 1],ans);
}
cout << ans<< endl;
}
return 0;
}
Codeforces 1554B 题目链接:点击这里传送
题意:
选取任意一对数,定义f(i,j)是 i
×
\times
×j-k
×
\times
×(a[i]|a[j]) 的值,求f(i,j)的最大值
思路:
根据二进制的位运算可得k
×
\times
×(a[i]|a[j])的最大值无非就是2
×
\times
×max(a[i],a[j])
×
\times
×k,而前面的i
×
\times
×j大小早就起飞了,两个导数完全不在一个量级上。所以就变成了贪心的思路,使得i和j尽可能大,然后在二层循环遍历找最大值。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
long long t, n,k;
long long a[MAXN];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> n>>k;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++) cin >> a[i];
long long ans = -9999999999999;
if (n > 400)
{
for (long long i = n-400; i < n; i++)
{
for (long long j = i + 1; j <= n; j++)
{
ans = max(ans, i * j - k * (a[i] | a[j]));
}
}
}
else
{
for (int i = 1 ; i < n; i++)
{
for (int j = i + 1; j <= n; j++)
{
ans = max(ans, i * j - k * (a[i] | a[j]));
}
}
}
cout << ans<<endl;
}
return 0;
}