题意:A、B在玩博弈游戏。其中一局分为X个小局,赢下Y个大局之后获得最终胜利,结束游戏(X,Y未知)。给定一个只包含字母A和B的序列,分别代表了A获胜和B获胜。问最终胜利者是谁。
思路:顺着题意来发现由于X,Y都未知,非常难判断谁在一局中赢了。但是逆着想会发现:当有人赢了Y个大局之后游戏直接结束了。因此赢得最后一小局的人也就赢得了游戏。
// Problem: A. Secret Sport
// Contest: Codeforces - Codeforces Round 908 (Div. 2)
// URL: https://codeforces.com/contest/1894/problem/0
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
void solve()
{
int n;
cin>>n;
string s;
cin>>s;
int cntA = 0 , cntB = 0;
cout<>t;
while(t--)
{
solve();
}
return 0;
}
题意:给定一个长度为n的数组a,要求构造长度为n的只包含1 , 2 , 3的数组b,其中必须恰好满足以下三个中的两个条件:
1、
2、
3、
思路:若有三个数相等,他们下标在b数组上分别为1、2、3,那么将同时满足3个条件,不满足题意。因此对于相等的数而言,只能选其中一个条件进行满足。要求刚好满足两个条件,则至少需要两个不同的数在数组中存在相等的数。让他们分别满足两个条件,其余的数全部置1即可。
// Problem: Two Out of Three
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/B
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
void solve()
{
int n;
cin>>n;
int a[n];
for(int i = 0 ; i < n ; i ++)
cin>>a[i];
mapmp;
int ans[n];
int flag = 0;
for(int i = 0 ; i < n ; i ++){
mp[a[i]]++;
if(mp[a[i]] == 1){
ans[i] = 1;
}
else if(mp[a[i]] == 2){
if(flag == 0){
ans[i] = 2;
flag ++;
}
else if(flag == 1){
ans[i] = 3;
flag ++;
}
else{
ans[i] = 1;
}
}
else{
ans[i] = 1;
}
}
if(flag == 2){
for(int i = 0 ; i < n ; i ++){
cout<>t;
while(t--)
{
solve();
}
return 0;
}
题意:给定一个长度为n的数列b,要求构造出数列a,问是否能够用k次操作将a数组转化成b数组。操作步骤如下:
1、选定a数组中的一个点,要求。
2、将整个数组向左移动 i 位。()
思路:同样考虑逆推,由于每次操作选定的都会在操作之后变为数组的最后一位,那么b数组的最后一位就是最后一次操作选择的。如此不断逆推k次,若期间出现了循环,则一定能够构造出a,使得k次操作后变为b。若期间出现了逆推得到的的情况,则代表无法选择该数进行操作,则代表操作无法进行,则代表无法构造出a。
// Problem: Anonymous Informant
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/C
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
void solve()
{
int n , k;
cin >> n >> k;
int a[n];
for(int i = 0 ; i < n ; i ++){
cin>>a[i];
}
int left = 0;
int st = n - 1;
mapmp;
mp[0] = 1;
for(int i = 0 ; i < min(n , k) ; i ++){
if(a[st - left] > n){
cout<<"No\n";
return;
}
left += a[st - left];
left %= n;
if(mp[left] == 0){
mp[left]++;
}
else{
cout<<"Yes\n";
return;
}
}
cout<<"Yes\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
题意:给定数组a和b,要求将两个数组合并,其中a数组上数的相对位置无法改变。要求合并后的数组LIS(最长递增子序列)的长度最小。
思路:直接贪心就行,甚至不用求LIS...要求LIS最小,那么b数组可以从大到小排序。然后考虑合并过程,两数组都从头开始合并,若此时a数组的数大于b数组的数,则将a数组的数放到前面,反之b数组的数放到前面(尽可能保证LIS = 1)。
// Problem: Neutral Tonality
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/D
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
const int INF = 1e9;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int cmp1(int a , int b){
return a > b;
}
struct Node{
int val,num;
}z[maxn];
int T[maxn];
int NN;
void solve()
{
int n , m;
cin>>n>>m;
int a[n] , b[m];
for(int i = 0 ; i >a[i];
for(int i = 0; i < m ; i ++)
cin>>b[i];
sort(b ,b + m , cmp1);
NN = m + n;
int id = 1;
for(int l = 0 , r = 0 ; l < n || r < m ;){
if(l < n && r < m){
if(a[l] > b[r]){
z[id].num = id , z[id].val = a[l];
l++;
}
else{
z[id].num = id , z[id].val = b[r];
r++;
}
}
else if(l < n){
z[id].num = id , z[id].val = a[l];
l++;
}
else{
z[id].num = id , z[id].val = b[r];
r++;
}
id++;
}
for(int i = 1 ; i <= NN ; i ++){
cout<>t;
while(t--)
{
solve();
}
return 0;
}
比赛时差点出来了,还是没想清楚。
题意:定义一个multiset(多重集合)的价值为集合当中等于集合长度的元素的数量。现你有一个初始空multiset,接下来给定m个multiset,然后给定k , l , r。代表了multiset中有k个不同元素,且必须要选择[L,R]个元素放入到你的multiset中。然后一行给出了每个元素的值,再一行给出了每个元素的个数。求最终你的multiset的价值最小值。
思路:首先考虑到元素的范围很大,而元素个数比较小,因此可以用离散化处理。求答案的过程可以遍历每个元素,然后计算最少能选多少个该元素。在处理每个元素 x 的过程中,显然不能再遍历每个multiset,于是我们可以将multiset中所有元素分为 x 和 非x两种。那么答案就是看总共选的x个元素当中有多少个非x元素。然后我们发现:由于每个multiset中最少选L个元素,那么就有可能出现必须要选择x元素的情况,因此需要记录一下至少选L个元素的情况下选中了多少个x元素 。如此选完以后剩下的尽可能的不去选择x元素,然后发现:由于每个multiset中最多选择R个元素,因此并不是所有的非x元素都能被选中,因此还需要记录最多选R个元素的情况下有多少个非x元素没被选中 。因此最终选择了 。
// Problem: E. Freedom of Choice
// Contest: Codeforces - Codeforces Round 908 (Div. 2)
// URL: https://codeforces.com/contest/1894/problem/E
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
void solve()
{
LL l = 0 , r = 0;
int n;
cin>>n;
LL max_cnt = 0;
unordered_map< LL , LL > mp;
unordered_map< LL , LL > minn;
unordered_map< LL , LL > maxx;
vectorv[n];
vectorcnt[n];
LL res_st = 0;
for(int i = 0 ; i < n ; i ++){
LL k , ll , rr;
cin>>k>>ll>>rr;
l += ll , r += rr;
for(int j = 0 ; j < k ; j ++){
LL x;
cin>>x;
v[i].pb(x);
}
LL cntt = 0;
for(int j = 0 ; j < k ; j ++){
LL x;
cin>>x;
cntt += x;
cnt[i].pb(x);
mp[v[i][j]] += x;
}
for(int j = 0 ; j < k ; j ++){
maxx[v[i][j]] += max(1LL * 0 , cnt[i][j] - max(1LL * 0 ,(rr - (cntt - cnt[i][j]))));//在不可选中的数中有多少个x
minn[v[i][j]] += max(1LL * 0 , ll - (cntt - cnt[i][j]));//至少选x个是v[i][j]
}
res_st += cntt - rr;//共有这么多个数是不可选的
max_cnt += cntt;//共有max_cnt个数
}
LL ans = 2e18;
LL num_cnt = 0;
for(auto it : mp){
LL x = it.first;//选x个数
if(x >= l && x <= r)//若不包含了[L , R]之内的所有数,答案可以为0
num_cnt++;
else
continue;
LL cntt = minn[x];//至少这么多个
LL res = x - cntt ;//还需要这么多(全部拿其他数/拿完了再拿x)
LL res_car = max_cnt - mp[x] - res_st + maxx[x];//最多能选这么多个不是x的数
cntt += max(1LL * 0 , res - res_car);
ans = min(ans , min(mp[x] , cntt));
}
if(r - l >= num_cnt){
cout<<0<>t;
while(t--)
{
solve();
}
return 0;
}