2022.4.10
AtCoder Regular Contest 138
A - Larger Score
搞个结构体,存储每个点的值和位置,从大到小排序,当值相等时位置小的在前面。利用pos和ans找到当前大于k且id最小的点,和小于k的点,不断更新最小值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=4e5+10,INF=1e9;
struct node
{
int val, id;
} a[N];
bool cmp(node a,node b)
{
if(a.val==b.val)
{
return a.id < b.id;
}
return a.val > b.val;
}
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n;i++)
{
int x;
cin >> x;
a[i] = {x, i};
}
sort(a + 1, a + 1 + n,cmp);
int pos = 1e9, ans = 1e9;
for (int i = 1; i <= n;i++)
{
if(a[i].id>k)
{
pos = min(pos, a[i].id);
}
else
{
ans = min(ans, pos-a[i].id);
}
}
if(ans>n)
cout << -1;
else
cout << ans;
return 0;
}
B - 01 Generation
反向操作一遍看能不能把序列变成空序列。一种操作是在开头加个0并把后面的数都翻转,第二种操作是在末尾加0.首先知道不论哪种操作1都肯定不会在第一位,所以反向操作的时候如果开头为1就可以直接判断no了,否则不断把队尾的0删掉,然后队头删掉再把后面的反转,直到i>j。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
int a[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
for (int i = 1; i <= n;i++)
cin >> a[i];
if(a[1]==1)
{
cout << "No" << '\n';
}
else
{
int f = 1,ans=0;
for (int i = 1, j = n; i <= j;)
{
if(!(a[i]^f))
{
ans=1;
break;
}
if(a[j]^f)
{
j--;
}
else
{
i++;
f ^= 1;
}
}
if(!ans)
cout << "Yes";
else
cout << "No";
}
return 0;
}
Educational Codeforces Round 126 (Rated for Div. 2)
A. Array Balancing
如果交换完的绝对值比交换前的小的话就交换。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int a[N], b[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
for (int i = 1; i <= n;i++)
cin >> a[i];
for (int i = 1; i <= n;i++)
cin >> b[i];
for (int i = 1; i <n;i++)
{
if(abs(a[i]-a[i+1])+abs(b[i]-b[i+1])>abs(b[i]-a[i+1])+abs(a[i]-b[i+1]))
swap(a[i+1], b[i+1]);
}
ll sum = 0;
for (int i = 1;i<n;i++)
{
sum += abs(a[i] - a[i + 1]);
sum += abs(b[i] - b[i + 1]);
}
cout << sum << '\n';
}
return 0;
}
B. Getting Zero
32768是2的15次方,需要把一个数变成2^15次方x,取模即为0。对于这个数我们可以选择加1或者2,于是可以枚举+1和*2的操作,取得最小值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9,mod=32768;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
for (int i = 1; i <= n;i++)
{
int x,ans=INF;
cin >> x;
for (int j = 0; j <= 15;j++)
{
int xx = (x + j) % mod;
int cnt = j;
while(xx)
{
xx = xx * 2 % mod;
cnt++;
}
ans = min(ans, cnt);
}
cout << ans << ' ';
}
return 0;
}
C. Water the Trees
然你求吧所有树都变成同样高度的最小次数,奇数天高度加一,偶数天高度加二,未必长到和最高的树一样的高度就是花费最小的,如:1 1 1 1 2。但所有树为max+1时花费最小。但不可能为max+2,因为这样可以用1来代替2。可以利用二分来写,满足时间的单调性,二分天数mid,在mid天里有(mid-1)/2天可以+1,有mid-cnt1天可以加2。基于贪心的策略我们应该先把+2的次数用完剩下的考虑用+1来补充,因此对于mid我们计算出所有树减去+2后需要的+1的次数,如果+1次数充足的满足,r=mid,否则+1次数不够不满足,为l=mid+1.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=3e5+10,INF=1e9;
int a[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n,mmax=-1;
cin>>n;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
mmax = max(mmax,a[i]);
}
ll ans = 1e18;
for (ll i = mmax; i <= mmax + 1;i++)
{
ll l = 0, r = 1e18;
while(l<r)
{
ll mid = l + r >> 1;
ll cnt1 = (mid + 1) / 2, cnt2 = mid - cnt1;
ll need1 = 0;
for (int j = 1; j <= n;j++)
{
ll now = (i - a[j]) / 2;
if((i-a[j])%2==1)
{
need1++;
}
if(cnt2>=now)
{
cnt2 -= now;
}
else
{
now -= cnt2;
cnt2 = 0;
need1 += now * 2;
}
}
if(need1<=cnt1)
{
r = mid;
}
else
l = mid + 1;
}
ans = min(ans, l);
}
cout << ans << '\n';
}
return 0;
}
SZTU Monthly 2022 Mar.
D (1322) : 切木棍
可知最后一定是化为平均值,二分操作次数,注意是(a[i]-1)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int a[N],n, k;
bool check(int mid)
{
int ans = 0;
for (int i = 1; i <= n;i++)
{
ans += (a[i]-1) / mid ;
}
return ans <= k;
}
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin >> n >> k;
int mmax = -1;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
mmax = max(a[i], mmax);
}
if(k==0)
{
cout << mmax;
}
else
{
int l = 1, r = 1e9+1;
while(l<r)
{
int mid = l + r >> 1;
if(check(mid))
r=mid;
else
l = mid + 1;
}
cout << r << '\n';
}
return 0;
}
J (1328) : 吃奶酪
转态压缩当前的状态注意从1开始选取当前最小的点开始搜索,在任意的时刻,dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+w[k][j]),异或是因为当前转态和上一个状态只能有一个点在j,然后对于每一位是1的位k,我们可以由k转移到j,于是记录一下转移的最小值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=17,INF=1e9;
double a[N], b[N],dis[1<<N][N];
double dist(double x1,double y1,double x2,double y2)
{
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin>>n;
for (int i = 1; i <= n;i++)
{
cin >> a[i] >> b[i];
}
for (int i = 0; i <= (1 << (n+1)) ;i++)
{
for (int j = 0; j <= n;j++)
{
dis[i][j] = 1e8*1.0;
}
}
dis[1][0] = 0;
for (int i = 1; i < 1 << (n+1) ;i++)
{
for (int j = 1; j <= n;j++)
{
if((i>>j)&1)
{
for (int k = 0; k <= n;k++)
{
if(i-(1<<j)>>k&1)
{
double distt = dist(a[j], b[j], a[k], b[k]);
dis[i][j] = min(dis[i][j], dis[i-(1<<j)][k] + distt);
}
}
}
}
}
double ans = 1e8 * 1.0;
for (int i = 1; i <= n;i++)
{
ans = min(ans, dis[(1 << (n+1))-1][i]);
}
printf("%.2lf", ans);
return 0;
}
B (1320) : 上色
利用multiset自带的二分找到大于当前数的位置,如果不存在则直接插入,删除该数并插入当前的数,每个数就相当于一个序列里的最大的数,最后输出set的大小即为满足的序列的个数。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
int a[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n;
while(cin>>n)
{
multiset<int> st;
for (int i = 1; i <= n;i++)
cin >> a[i];
for (int i = 1; i <= n;i++)
{
auto t = st.lower_bound(a[i]);
if(t==st.begin())
{
st.insert(a[i]);
}
else
{
t--;
st.erase(t);
st.insert(a[i]);
}
}
cout << st.size()<<'\n';
}
return 0;
}
C (1321) : 第k小
二分+二分,第一次二分是找当前第k小的数,第二次二分是二分是看这个数是否满足第k小,将整个分为小于0和大于等于0这两部分,二分负的有多少对乘积小于x再二分正的,最后再二分正的和负的,需要注意负数二分需要revese,因为两个负数相乘越小乘完越大,最后正负相乘的时候也需要注意。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
vector<ll> a, b;
ll n, k;
bool check(ll x)
{
ll ans = 0;
sort(a.begin(), a.end(),greater<ll>());
sort(b.begin(), b.end());
int n = a.size(), m = b.size();
for (int i = 0; i < n;i++)
{
ll l = i, r = n-1;
while(l<r)
{
ll mid = l + r + 1>> 1;
if(a[i]*a[mid]<=x)
{
l = mid;
}
else
r = mid - 1;
}
if(l>i)ans += l - i;
}
for (int i = 0; i < m;i++)
{
ll l = i, r = m-1;
while(l<r)
{
ll mid = l + r+1>> 1;
if(b[i]*b[mid]<=x)
{
l = mid;
}
else
r = mid - 1;
}
if(l>i) ans += l - i;
}
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
for (int i = 0; i < n;i++)
{
ll l = -1, r = m - 1;
while(l<r)
{
ll mid = l + r +1 >> 1;
if(a[i]*b[mid]<=x)
{
//res = mid;
l = mid;
}
else
r = mid - 1;
}
if(l!=-1) ans += l + 1;
}
return ans >= k;
}
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin >> n >> k;
for (int i = 1; i <= n;i++)
{
ll x;
cin >> x;
if(x<0)
a.push_back(x);
else
b.push_back(x);
}
ll l = -1e18, r = 1e18 ;
sort(a.begin(), a.end(),greater<ll>());
sort(b.begin(), b.end());
while(l<r)
{
ll mid = l + r >> 1;
if(check(mid))
{
r = mid;
}
else
l = mid + 1;
}
cout << l;
return 0;
}
Codeforces Round #640 (Div. 4)
A. Sum of Round Numbers
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
string n;
cin>>n;
int cnt = 0;
reverse(n.begin(), n.end());
for (int i = 0; i <n.size();i++)
{
if(n[i]!='0')
{
cnt++;
}
}
cout << cnt << '\n';
for (int i = 0; i < n.size(); i++)
{
if(n[i]!='0')
{
int x = n[i] - '0';
cout << x * (pow(10,i)) << ' ';
}
}
cout << '\n';
}
return 0;
}
B. Same Parity Summands
留出最后一个数,如果当前数能被分成若干的2或1相加,最后再加上留出的数就行,否则不行
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n, k;
cin>>n>>k;
k--;
int cnt1 = n - k, cnt2 = n - 2 * k;
if(cnt2%2==0&&cnt2>0)
{
cout << "YES" << '\n';
for (int i = 1; i <= k;i++)
{
cout << '2' << ' ';
}
cout << cnt2 << '\n';
}
else if(cnt1&1&&cnt1>0)
{
cout << "YES" << '\n';
for (int i = 1; i <= k;i++)
{
cout << '1' << ' ';
}
cout << cnt1 << '\n';
}
else
cout << "NO" << '\n';
}
return 0;
}
C. K-th Not Divisible by n
如果不能被n整除说明前面n-1个肯定是一组的只有n被拿掉了,我们可以根据k里有多少个(n-1)这样的组,因此为ans*n。如果cnt为0说明最后一个数整除了,因此需要去掉。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
ll n,k;
cin >> n >> k;
ll ans = k / (n - 1);
ll cnt = k % (n - 1);
if(cnt!=0)
{
cout << ans * n + cnt<<'\n';
}
else
{
cout << ans * n - 1<<'\n';
}
}
return 0;
}
D. Alice, Bob and Candies
模拟
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e3+10,INF=1e9;
int a[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
int sum = 0;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
sum += a[i];
}
int cnt=0 ,sum1=0, sum2 = 0,now=0;
for (int i = 1; i <= n;)
{
cnt++;
int sum = a[i++];
while(sum<=now&&i<=n)
sum += a[i++];
sum1 += sum;
now = sum;
if(i>n)
break;
cnt++;
sum = a[n--];
while(sum<=now&&i<=n)
sum += a[n--];
sum2 += sum;
now=sum;
}
cout << cnt << ' ' << sum1 << ' ' << sum2 << '\n';
}
return 0;
}
E. Special Elements
问你区间是否存在某段连续的段其和为数组的任意一个数ai。求出满足的ai的个数。利用双指针,枚举每个点为开头,sum不断吗相加直到超过n,(因为最大的ai不超过n),每次加一个数的时记录sum,如果sum在之前出现过那么对答案贡献为1否则为0,每次加完之后都要清空,防止重复。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=8000+10,INF=1e9;
int a[N],vis[N];
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n;i++)
{
cin >> a[i];
vis[a[i]]++;
}
int ans = 0;
for (int i = 1; i < n;i++)
{
int sum = a[i];
for (int j = i + 1; j <= n;j++)
{
sum += a[j];
if(sum>n)
continue;
ans += vis[sum];
vis[sum] = 0;
}
}
cout << ans << '\n';
}
return 0;
}
F. Binary String Reconstruction
给你n0,n1,n2,表示01字符串01的和,让你构造出该字符串。
如果当n1为0的话我们可以直接构造出n0和n2的情况,只需在n0的基础上多输出一个0即可。
当n1不为0的时候我们首先构造出n1个10在加1个0或1.然后在第一个0之前补充n0个0,第一个1之前补充n1个1,因为此时已经包含有一个1和一个0了,因此不需要额外输出
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int sum0, sum1, sum2;
cin >> sum0>> sum1>>sum2;
if(sum1==0)
{
if(sum0)
{
for (int i = 1; i <= sum0+1;i++)
{
cout << '0';
}
}
if(sum2)
{
for (int i = 1; i <= sum2+1;i++)
{
cout << '1';
}
}
cout << '\n';
continue;
}
string s;
for (int i = 1; i <= sum1 + 1;i++)
{
if(i&1)
{
s += '1';
}
else
s += '0';
}
s.insert(1, string(sum0, '0'));
s.insert(0, string(sum2, '1'));
cout << s << '\n';
}
return 0;
}
G. Special Permutation
想的比较复杂去了,思维还是不够。其实两个偶数或奇数都是差2,只需要从大到小输出奇数,最后再加上4和2保证差在2-4之间,然后再从大到小输出偶数就行了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
if(n<4)
{
cout << "-1" << '\n';
continue;
}
for (int i = n; i >= 1;i--)
{
if(i&1)
cout << i << ' ';
}
cout << "4 2 ";
for (int i = 6; i <= n;i+=2)
{
cout << i << ' ';
}
cout << '\n';
}
return 0;
}