第七天打卡 Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)
A题:找出有多少个每一个位置上数字都相同的数。
模拟即可。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
int pos[100];
int main()
{
t = read();
while (t--)
{
n = read();
int nums = 0;
int tempn = n;
while (tempn)
{
pos[++nums] = tempn % 10;
tempn /= 10;
}
int tempnum = nums;
int sum = 0;
while (tempnum)
{
sum *= 10;
sum++;
tempnum--;
}
sum *= pos[nums];
int ans = 0;
ans += 9 * (nums - 1);
ans += n >= sum ? (pos[nums]) : (pos[nums] - 1);
printf("%d\n", ans);
}
return 0;
}
B题
题意:每一次可以使得相等的数字除以二,问最少次操作使得数组全部变成奇数。
暴力模拟,开一个set,每一次贪心用最大的来除以2,再暴力合并进入set。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 2e5 + 10;
int a[N];
set<int>s;
int main() {
t = read();
while (t--) {
n = read();
upd(i, 1, n)
{
a[i] = read();
if (a[i] % 2 == 0)
{
s.insert(a[i]);
}
}
int ans = 0;
while (!s.empty())
{
int top = *(--s.end());
if (top % 2)s.erase(*(--s.end()));
else
{
s.erase(*(--s.end()));
ans++;
top /= 2;
s.insert(top);
}
}
cout << ans << endl;
}
}
c题
题意:给一个字符串,问不能有one和two,每一次操作删掉一个字符,问最小操作。
可以发现,one和two最多公用一个o,也就是重叠出 twone这种情况。我们特判这种情况,删掉o相当于去除两个不正确的字符串。其他分别判断two和one即可。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 2e5 + 10;
char s[N];
int pos[N];
int main()
{
t = read();
while (t--)
{
scanf("%s", s + 1);
n = strlen(s + 1);
upd(i, 1, n)pos[i] = 0;
string ss;
upd(i, 1, n-2) {
ss = "";
upd(j, i, i + 2)
{
ss += s[j];
}
if (ss == "two")pos[i] = 2;
if (ss == "one")pos[i] = 1;
}
int ans = 0;
vector<int>vec;
upd(i, 1, n)
{
if (pos[i])
{
if (pos[i] == 1)
{
if (i > 2 && pos[i - 2] == 2)
{
vec.pop_back();
vec.push_back(i);
continue;
}
else
{
ans++;
if (i > 1)
{
if (s[i-1] == 'o')vec.push_back(i + 1);
else vec.push_back(i);
}
else
vec.push_back(i);
}
}
else
{
if (i > 1)
{
if (s[i - 1] == 't')vec.push_back(i + 1);
else vec.push_back(i);
}
else vec.push_back(i);
ans++;
}
}
}
printf("%d\n", ans);
for (auto k : vec)
{
printf("%d ", k);
}
cout << endl;
}
return 0;
}
D题
题意:给出n个01字符串,要求首尾相连,不能有重复字符串。每一次操作可以使得一个字符串反转,求最小操作次数。
考虑收尾两个字符,我们将字符串缩小成为两个字符。
我们可以发现,01,10之间,可以加入n个11字符串,然后又可以再末尾加入n个00.所以错误情况有,同时又11和00且没有任何10和01。
继续判断10和01的关系,10和01必须保持差1或者相等才能完全匹配。
我们暴力模拟该过程即可。b
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 2e5 + 10;
string s[N];
map<string, int>mp;
vector<int>vec[5];
int lf[N], rt[N];
vector<int>ans;
int main()
{
t = read();
while (t--)
{
n = read();
up(i, 0, 4)vec[i].clear(); mp.clear(); ans.clear();
upd(i, 1, n)
{
cin >> s[i];
mp[s[i]] = 1;
if (s[i].front() == '0' && s[i].back() == '1')vec[1].push_back(i);
if (s[i].front() == '1' && s[i].back()== '0')vec[2].push_back(i);
if (s[i].front() == '0' && s[i].back() == '0')vec[0].push_back(i);
if (s[i].front() == '1'&&s[i].back() == '1')vec[3].push_back(i);
}
if (vec[3].size() && vec[0].size() && vec[1].size() == 0 && vec[2].size() == 0) { printf("%d\n", -1); continue; }
int x = vec[1].size();
int y = vec[2].size();
string temps="";
if (x > y)
{
int cnt = 0;
while (y + 1 < x&&cnt<vec[1].size())
{
int v = vec[1][cnt];
temps = s[v];
reverse(temps.begin(), temps.end());
if (mp[temps])
{
cnt++;
continue;
}
else
{
ans.push_back(v);
y++; x--; cnt++;
}
}
if (abs(y - x) <= 1)
{
printf("%d\n", ans.size());
for (auto k : ans)
{
printf("%d ", k);
}
cout << endl;
}
else
{
printf("%d\n", -1);
continue;
}
}
else
{
int cnt = 0;
while (x + 1 < y&&cnt < vec[2].size())
{
int v = vec[2][cnt];
temps = s[v];
reverse(temps.begin(), temps.end());
if (mp[temps])
{
cnt++;
continue;
}
else
{
ans.push_back(v);
x++; y--; cnt++;
}
}
if (abs(x - y) <= 1)
{
printf("%d\n", ans.size());
for (auto k : ans)
{
printf("%d ", k);
}
cout << endl;
}
else
{
printf("%d\n", -1);
continue;
}
}
}
}
E题
题意:给出一个图,给出两个点a,b,问有多少对其他点,要求这对点的所有路径都经过给出的两个点。
先分析一下什么情况不行。当一个点,不通过a直接连接b,而且不通过b能直接连接到a,那么该点不能和其他任何点进行匹配。
换句话说,每一个点当且仅当,能直连a的时候,不能直连b,或者能直连b的时候不能直连a,该点符合题意。
我们去掉点a,dfs b点,去掉点b,dfs a点,最后再去除相同的项,就能找到上述满足题意的点。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
const int node_N = 2e5 + 10;
vector<int>vec[node_N];
int t;
int n, m, a, b;
int vis[node_N];
set<int>s1, s2;
void dfs(int u,int flag)
{
vis[u] = 1;
for (auto k : vec[u])
{
if (!vis[k])
{
if (flag == 2)s2.insert(k);
else s1.insert(k);
dfs(k,flag);
}
}
}
int main()
{
t = read();
while (t--)
{
s1.clear(); s2.clear();
memset(vis, 0, sizeof(vis));
n = read(), m = read(), a = read(), b = read();
upd(i, 0, n)vec[i].clear();
int u, v;
upd(i, 1, m)
{
u = read(), v = read();
vec[u].push_back(v);
vec[v].push_back(u);
}
vis[a] = 1;
dfs(b,2);
memset(vis, 0, sizeof(vis));
vis[a] = 0; vis[b] = 1;
dfs(a,1);
vector<int>er;
for (auto k : s1)
{
// cout << "K" << k << endl;
if (s2.count(k))
{
er.push_back(k);
s2.erase(k);
}
}
for (auto k : er)s1.erase(k);
printf("%lld\n", 1ll * s1.size()*s2.size());
}
return 0;
}
F题
讲道理我觉得这个构造题蛮好的。
一开始我是这么做的,找到最大的相同数字,和相同数字的数量,做dp,令dp[i]表示宽为w的时候,最多能放多少个。然后暴力枚举w,找到最大。然后放置的时候我是先放上三角,再放下三角。
后来发现这样做没有过样例二,觉得很奇怪。
赛后看了看了别人的提交。发现自己脑残了。
正解:我们同样令dp[i]表示宽为w的时候,最多能放多少个。宽为w的时候,最多能放置,w个同样的数字。
我们以这样的思维来放置,从对角线出发放置,如果往右走到边界,跳到左边继续放置。这样能保证一定不重复。首先高不同,行内不重复。其次,如果跳转到左边,那么列不重复。倘若没有跳转,同一条对角线上,元素不重复,且我们优先计算了w,保证了最多w个同样的数字,即对角线个。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 4e5 + 10;
int n;
int a[N];
int dp[N];
map<int, int>mp1,num;
vector<pir>vec;
int main()
{
n = read();
upd(i, 1, n)
a[i] = read();
upd(i, 1, n)mp1[a[i]]++;
int kind = 0;
for (auto k : mp1)num[k.second]++,kind++;
upd(i, 1, n)
{
dp[i] = dp[i - 1] + kind;
kind -= num[i];
}
int now_h=0, now_w=0;
upd(i, 1, n)
{
int w = dp[i] / i;
if (w >= i) {
if (now_h*now_w < w*i)
{
now_h = i;
now_w = w;
}
}
}
printf("%d\n%d %d\n", now_h*now_w, now_h, now_w);
for (auto k : mp1)vec.push_back(make_pair(k.second, k.first));
sort(vec.begin(), vec.end(),greater<pir>());
queue<int>que;
for (auto k : vec)upd(i, 1, min(k.first, now_h))que.push(k.second);
vector<vector<int> >ans(now_h, vector<int>(now_w, 0));
up(j, 0, now_w)
{
int temp_w = j;
up(i, 0, now_h)
{
ans[i][temp_w] = que.front(); que.pop();
// cout << ans[i][temp_w] << " " << "i" << i << " temp_w" << temp_w << endl;
temp_w++; temp_w %= now_w;
}
}
up(i, 0, now_h) {
up(j, 0, now_w) {
printf("%d ", ans[i][j]);
}
printf("\n");
}
return 0;
}