Round 75 Rated for Div. 2)
比赛网址:https://vjudge.net/contest/381170
codeforce的网址:https://codeforces.com/contest/1251
A( Rated for Div. 2 E1)看G
B( Rated for Div. 2 C)
题意:
可以交换奇偶性不同的相邻的数,然后获得最小的数。
思路:
我的思路:
找到奇偶性不同的数然后进行交换,然后与之前的数进行比较,然后循环进行,知道找到最小的那个最后输出,我感觉应该运用到了记忆数组的那一部分的知识。
官方思路:
让我们考虑两个数字序列:e1,e2,…,ek和o1,o2,…,om,在那里e1中的第一个偶数a, e2是第二个偶数,以此类推o1中的第一个奇数a, o2是第二个奇数,以此类推。
由于不能交换相同奇偶的数字,所以序列e的偶数位数a从未改变过。序列o的奇数a也从未改变过。所以答案中的第一个数字等于e1或去o1。由于我们必须将答案最小化,所以我们必须选择min(e1,o1)作为答案中的第一个数字,他们将其从相应的序列中删除(以这种方式)e转成e2,e3,…,ek或序列o转成o2,o3,…,om)。第二,第三位和下面的数字需要以同样的方式选择。
官方代码:
#include <bits/stdc++.h>
using namespace std;
int t;
string a;
int main() {
cin >> t;
for(int tc = 0; tc < t; ++tc){
cin >> a;
string s[2];
for(auto x : a)
s[int(x - '0') & 1] += x;
reverse(s[0].begin(), s[0].end());
reverse(s[1].begin(), s[1].end());
string res = "";
while(!(s[0].empty() && s[1].empty())){
if(s[0].empty()){
res += s[1].back();
s[1].pop_back();
continue;
}
if(s[1].empty()){
res += s[0].back();
s[0].pop_back();
continue;
}
if(s[0].back() < s[1].back()){
res += s[0].back();
s[0].pop_back();
}
else{
res += s[1].back();
s[1].pop_back();
}
}
cout << res << endl;
}
return 0;
}
C( Rated for Div. 2 A)
题意:
一个字符串,输入的时候如果出现偶数个则是坏了,如果是奇数个就是正常,然后找出坏的。
思路:
就是找到相同连续的导出就可以了
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,m,maxx,ans,aans,flag,a[30];
string s;
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
cin>>s;
n=s.size();
for(int i=0;i<n;i++)
{
if(i==n-1||(i!=n-1&&s[i]!=s[i+1])) a[s[i]-'a']=1;
else if(i!=n-1&&s[i]==s[i+1]) i++;
}
for(int i=0;i<=26;i++)
{
if(a[i]) cout<<char(i+'a');
}
cout<<endl;
}
return 0;
}
D( Rated for Div. 2 D)
题意:
n 有人为你工作,你必须把工资分配给你的雇员。一开始,你s给它的钱,还有i-该雇员应从li到ri美元。你必须以这样一种方式分配工资,即工资中位数是最大可能.要找到奇数长度序列的中间值,必须对其进行排序,并在排序后取中间位置的元素。找到可以获得的最大中位数薪资。
思路:
我的思路:
找到中间的,然后和前后进行比较,应该是要运用到二进制的知识点。
官网思路:
放任f(mid)至少要有相等的最低金额才能获得工资的中位数。mid。我们将通过二进制搜索来解决这个问题mid.
假设必须计算获得中位数工资的最低金额。mid。让我们把所有的工资分成三组:
ri<mid;
mid≤li;
li<mid≤ri.
为了达到工资的中位数mid至少一定有n+12高于或等于mid。让我们表示一下cnt.
注意,第一组的薪资不能增加cnt因此,为这个群体支付最低工资对我们是有益的。如果第二组总是增加cnt所以支付最低工资对我们也是有益的。
第三组的薪水更有趣。按每一薪金计算[li,ri]在这组中我们可以支付mid增量cnt或者我们可以li不要增加cnt。价值cnt应该增加rem=max(0,n+12−cnt)。所以,如果第三组的大小小于rem我们无法获得工资中位数mid。否则,我们可以定义我们可以拿多少工资值。li选择了最小的。
#include <bits/stdc++.h>
using namespace std;
const int N = int(2e5) + 99;
const int INF = int(1e9) + 100;
int t;
int n;
long long s;
pair<int, int> p[N];
bool ok(int mid){
long long sum = 0;
int cnt = 0;
vector <int> v;
for(int i = 0; i < n; ++i){
if(p[i].second < mid)
sum += p[i].first;
else if(p[i].first >= mid){
sum += p[i].first;
++cnt;
}
else
v.push_back(p[i].first);
}
assert(is_sorted(v.begin(), v.end()));
int need = max(0, (n + 1) / 2 - cnt);
if(need > v.size()) return false;
for(int i = 0; i < v.size(); ++i){
if(i < v.size() - need)
sum += v[i];
else
sum += mid;
}
return sum <= s;
}
int main() {
scanf("%d", &t);
for(int tc = 0; tc < t; ++tc){
scanf("%d %lld", &n, &s);
for(int i = 0; i < n; ++i)
scanf("%d %d", &p[i].first, &p[i].second);
sort(p, p + n);
int lf = 1, rg = INF; ///WA -> 10^9
while(rg - lf > 1){
int mid = (lf + rg) / 2;
if(ok(mid)) lf = mid;
else rg = mid;
}
printf("%d\n", lf);
}
return 0;
}
E( Rated for Div. 2 F)
题意:
#include<bits/stdc++.h>
using namespace std;
const int LOGN = 20;
const int N = (1 << LOGN);
const int MOD = 998244353;
const int g = 3;
#define forn(i, n) for(int i = 0; i < int(n); i++)
inline int mul(int a, int b)
{
return (a * 1ll * b) % MOD;
}
inline int norm(int a)
{
while(a >= MOD)
a -= MOD;
while(a < 0)
a += MOD;
return a;
}
inline int binPow(int a, int k)
{
int ans = 1;
while(k > 0)
{
if(k & 1)
ans = mul(ans, a);
a = mul(a, a);
k >>= 1;
}
return ans;
}
inline int inv(int a)
{
return binPow(a, MOD - 2);
}
vector<int> w[LOGN];
vector<int> iw[LOGN];
vector<int> rv[LOGN];
void precalc()
{
int wb = binPow(g, (MOD - 1) / (1 << LOGN));
for(int st = 0; st < LOGN; st++)
{
w[st].assign(1 << st, 1);
iw[st].assign(1 << st, 1);
int bw = binPow(wb, 1 << (LOGN - st - 1));
int ibw = inv(bw);
int cw = 1;
int icw = 1;
for(int k = 0; k < (1 << st); k++)
{
w[st][k] = cw;
iw[st][k] = icw;
cw = mul(cw, bw);
icw = mul(icw, ibw);
}
rv[st].assign(1 << st, 0);
if(st == 0)
{
rv[st][0] = 0;
continue;
}
int h = (1 << (st - 1));
for(int k = 0; k < (1 << st); k++)
rv[st][k] = (rv[st - 1][k & (h - 1)] << 1) | (k >= h);
}
}
inline void fft(int a[N], int n, int ln, bool inverse)
{
for(int i = 0; i < n; i++)
{
int ni = rv[ln][i];
if(i < ni)
swap(a[i], a[ni]);
}
for(int st = 0; (1 << st) < n; st++)
{
int len = (1 << st);
for(int k = 0; k < n; k += (len << 1))
{
for(int pos = k; pos < k + len; pos++)
{
int l = a[pos];
int r = mul(a[pos + len], (inverse ? iw[st][pos - k] : w[st][pos - k]));
a[pos] = norm(l + r);
a[pos + len] = norm(l - r);
}
}
}
if(inverse)
{
int in = inv(n);
for(int i = 0; i < n; i++)
a[i] = mul(a[i], in);
}
}
int aa[N], bb[N], cc[N];
inline void multiply(int a[N], int sza, int b[N], int szb, int c[N], int &szc)
{
int n = 1, ln = 0;
while(n < (sza + szb))
n <<= 1, ln++;
for(int i = 0; i < n; i++)
aa[i] = (i < sza ? a[i] : 0);
for(int i = 0; i < n; i++)
bb[i] = (i < szb ? b[i] : 0);
fft(aa, n, ln, false);
fft(bb, n, ln, false);
for(int i = 0; i < n; i++)
cc[i] = mul(aa[i], bb[i]);
fft(cc, n, ln, true);
szc = n;
for(int i = 0; i < n; i++)
c[i] = cc[i];
}
vector<int> T[N];
int a[N];
int b[N];
int n, k;
int ans[N];
int Q[N];
int fact[N];
int rfact[N];
int auxa[N];
int auxb[N];
int auxc[N];
int C(int n, int k)
{
if(n < 0 || k < 0 || k > n) return 0;
return mul(fact[n], mul(rfact[k], rfact[n - k]));
}
vector<int> newtonExp(int a, int b, int p)
{
vector<int> res(p + 1);
for(int i = 0; i <= p; i++)
res[i] = mul(C(p, i), mul(binPow(a, i), binPow(b, p - i)));
return res;
}
int main()
{
precalc();
fact[0] = 1;
for(int i = 1; i < N; i++) fact[i] = mul(fact[i - 1], i);
for(int i = 0; i < N; i++) rfact[i] = inv(fact[i]);
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
for(int i = 0; i < k; i++) scanf("%d", &b[i]);
int q;
scanf("%d", &q);
for(int i = 0; i < q; i++) scanf("%d", &Q[i]);
map<int, int> cnt;
for(int i = 0; i < n; i++)
cnt[a[i]]++;
for(int i = 0; i < k; i++)
{
int redL = b[i];
int cnt1 = 0;
int cnt2 = 0;
for(auto x : cnt)
{
if(x.first >= redL)
break;
if(x.second == 1)
cnt1++;
else
cnt2++;
}
memset(auxa, 0, sizeof auxa);
memset(auxb, 0, sizeof auxb);
memset(auxc, 0, sizeof auxc);
vector<int> p1 = newtonExp(2, 1, cnt1);
vector<int> p2 = newtonExp(1, 1, cnt2 * 2);
int sa = p1.size();
int sb = p2.size();
int sc;
for(int j = 0; j < sa; j++)
auxa[j] = p1[j];
for(int j = 0; j < sb; j++)
auxb[j] = p2[j];
multiply(auxa, sa, auxb, sb, auxc, sc);
for(int j = 0; j < q; j++)
{
int cntW = Q[j] / 2 - redL - 1;
if(cntW >= 0 && cntW < sc)
ans[j] = norm(ans[j] + auxc[cntW]);
}
}
for(int i = 0; i < q; i++)
printf("%d\n", ans[i]);
}
F( Rated for Div. 2 B)
题意:
给你n个二进制字符串,然后你可以随意组合他们,
使他们形成原来的字符串相同长度的回文数组。
然后计算出最多可以形成几个回文数组。
思路:
我比赛时的思路:应该是先将最短的那个序列改为回文,然后再按长度一次进行改变。但是事实验证我这个想法漏洞不对。
大佬的思路:
首先字符串的长度是奇数的时候都是回文的状态,然后是偶数的时候如果要改为回文,那么0,1的个数一定是偶数个。那如果有至少一个奇数的时候,需要用这个奇数给其他的数进行修改。然后就可以所有的都改为回文,但是如果没有奇数的时候。
对于不能构成回文串的情况只有一种(奇数个1,奇数个0).
对于长度为奇数的字符串,一定能构成。因为奇数=偶数+奇数。所以这个要特判。
所以最终我们要找长度不是奇数且有奇数个1,奇数个0的情况就行。
代码网址:https://blog.youkuaiyun.com/qq_43690454/article/details/104105663
#include<bits/stdc++.h>
using namespace std;
int t,n;
char s[1000005];
int main()
{
cin>>t;
while(t--)
{
cin>>n;
int l=0,r=0,f=0;
for(int i=1;i<=n;i++)
{
cin>>s;
int m=strlen(s);
if(m&1) f=1;
for(int j=0;j<m;j++)
{
if(s[j]=='1') l++;
else r++;
}
}
if((l&1)&&(r&1)&&!f) n--;
cout<<n<<endl;
}
}
G( Rated for Div. 2 E2)
题意:
就是有n个人投票,然后对于第i个人如果有其它mi个人投票给你,那么他也会投票给你,不然你就得给他pi的钱才投给你。求怎样花钱少,输出钱数。
#include <bits/stdc++.h>
using namespace std;
const int N = int(3e5) + 99;
int t, n;
vector <int> v[N];
int main() {
int t;
scanf("%d", &t);
for(int tc = 0; tc < t; ++tc){
scanf("%d", &n);
for(int i = 0; i < n; ++i)
v[i].clear();
for(int i = 0; i < n; ++i){
int x, s;
scanf("%d %d", &x, &s);
v[x].push_back(s);
}
multiset <int > q;
long long res = 0;
int pref = n;
int cnt = 0;
for(int i = n - 1; i >= 0; --i){
pref -= v[i].size();
int need = i - pref;
for(auto x : v[i]) q.insert(x);
while(cnt < need){
++cnt;
res += *q.begin();
q.erase(q.begin());
}
}
printf("%lld\n", res);
}
return 0;
}
小总结:
我发现我的思路真的是很怪,然后对于不同的题目都有自己的看法,但是我的看法总是在代码的书写上搞不出来,但是感觉自己的思路也是可以的,但最后还是和大多数人不一样,应该还是自己的问题面对问题的思考方式要改变一下吧。其实我感觉应该是自己代码写得不好的问题,题目相同,思路每个人不同,应该是提高自己写代码的实力,把自己的代码搞出来。