废话:本来前50分钟kill完了A B C1 D的时候是前300,看着C2过的人很少就想着摆了,结果刷了会儿视频一看我都排到700了,这才开始做C2,结果到最后C2卡线过的,E应该能过也没时间想了。直接排名干到700+了。
Codeforces Round #829 (Div. 2)
正题
A. Technical Support(思维)
题意:给定一个qa序列,要求每个q后面都必须有a可以和他对应
分析:全场唯一一发wa是A题。
q后面必须有足够的a要大于等于目前的q的数量就可以了,当:目前的q被a匹配光了之后,不能继续克扣q的数量。
#include <iostream>
using namespace std;
#define int long long
#define endl '\n'
#define first fi
#define second se
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
char s[N];
int a[N];
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
{
int n;
cin>>n;
cin>>(s+1);
int now=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='Q')
{
now++;
}
else if(now>0)
{
now--;
}
}
if(now<=0)
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
return 0;
}
B. Kevin and Permutation(数列,思维)
题意:要求输出一个长度为n个排列,使得其相邻两项差值的最小值最大。
分析:一眼分块输出,不是中间开始分,就是奇偶分,再不然就是根号分。随便试一下发现是中间开始的数列分块(此分块非彼分块)
#include <iostream>
using namespace std;
#define int long long
#define endl '\n'
#define first fi
#define second se
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
char s[N];
int a[N];
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
{
int n;
cin>>n;
int l=n/2+n%2;
int r=n;
for(int i=1;i<=n;i++)
{
if(i&1)
{
cout<<l<<" ";
l--;
}
else
{
cout<<r<<" ";
r--;
}
}
cout<<endl;
}
return 0;
}
C2. Make Nonzero Sum (hard version)(思维,数学)
题意:给定一个只包含 1 0 -1的数组,请你把这个数组划分为若干的连续区间(l,r)。有一个函数sum(l,r)=a[l]-a[l+1]+a[l+2]-a[l+3]…a[r]这样,要求你划分的若干个区间的sum函数之和为0
思路:给的所有数如果和他相邻的下一项组合的话,那么就可以在保证本身符号不变的情况下扭转下一项的符号,所以实际上就变成了这样的一个题:
1.绝对值为1的数有贡献
2.有贡献的数前面的符号分为正负两种
3.当一个数前面有其他数的时候,可以扭转这个数的正负号,但是之后这两个数都不能再被选中。
4.正负号数量相等
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
const int N = 2e6+100;
int n,a[N],vis[N];
void init()
{
for(int i=1;i<=n;i++)
vis[i]=0;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
{
init();
cin>>n;
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]==1)
{
cnt1++;
}
else if(a[i]==-1)
{
cnt2++;
}
}
if(cnt1>cnt2)//情况1 1的数量多,需要扭转-1
{
for(int i=2;i<=n;i++)
{
if(a[i]==1)
{
vis[i-1]=vis[i]=1;
cnt1--;
cnt2++;
i++;
}
if(cnt1==cnt2)//扭转足够
{
break;
}
}
}
else if(cnt1<cnt2)//情况2 -1的数量多,扭转1的数量
{
for(int i=2;i<=n;i++)
{
if(a[i]==-1)
{
vis[i-1]=vis[i]=1;
cnt1++;cnt2--;
i++;
}
if(cnt1==cnt2)//扭转足够
{
break;
}
}
}
if(cnt1==cnt2)
{
vector<pair<int,int>>ans;
for(int i=1;i<=n;i++)
{
if(vis[i])
{
ans.push_back(make_pair(i,i+1));
i++;
}
else
{
ans.push_back(make_pair(i,i));
}
}
cout<<ans.size()<<endl;
for(auto x:ans)
{
cout<<x.first<<" "<<x.second<<endl;
}
}
else
{
cout<<-1<<endl;
}
}
return 0;
}
D. Factorial Divisibility(数论,进位)
题意:给定一个数组a和一个数x,判定这个数组的所有元素的阶乘和能否被x的阶乘整除。
思路:暴力?就算是简单也不会给你暴力的。
我们想想,如果y想被x整除的话,那么是不是y必须是x的倍数。
那么y是x的倍数的话,y一定不能比x小对吧?
回到这个题上来,所有元素的阶乘的和视为y,那么想办法判断能成为x的倍数即可。
比如x是6
然后你得有六个 5才行,因为这样才能爬到对应位
这样层层进位像是:两个一进一位2,三个2进一位1,四个3进一位4。
只要出现了进位后有余数的情况那么就可以判断不能被x!整除了。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e6+100;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
char s[N];
int a[N];
int sum[N];
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int n,m;
int t=1;
//cin>>t;
while(t--){
cin>>n>>m;
map<int,int>mp;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mp[a[i]]++;
}
bool falg=true;
for(int i=1;i<=m-1;i++)
{
if(mp[i]%(i+1)==0)
{
mp[i+1]+=mp[i]/(i+1);
}
else
{
falg=false;
}
}
if(falg)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
E. Wish I Knew How to Sort(概率期望,概率论)
题意:给定一个01串,每次可以选择一对下标[i,j] (i!=j),然后交换这两个下标对应的数,问你将整个串交换为有序的期望是多少。
思路:
抽象模型
首先假设我们有x个0,那么题目期望达到的最终状态就是前x个位置都是0,也就是要把前x个位置里的前的所有1都交换出去。
1.概率论基础:若干事件的期望是每个事件期望的和。
应用到这个题上就是:每个1被交换出去的期望相加。
再来每个1被交换出去的期望,发现一共有n*(n-1)/2个下标对可以选择,其中满足能把1交换出去的是cntcnt(cnt是当前遍历到的前x个位置中1的个数)个。所以成功选择的概率就是cnt * cnt/(n(n-1)/2)
2.伯努利事件与几何分布。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e6+100;
const int mod =998244353;
int fastpow(int n,int a)
{
int res=1;
a%=mod;
while(n)
{
if(n&1)
{
res=res*a%mod;
}
a=a*a%mod;
n>>=1;
}
return res%mod;
}
int a[N];
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t;
for(cin>>t;t;t--)
{
int n;
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(!a[i])
cnt++;
}
int x=0;
int tot=n*(n-1)/2;
tot%=mod;
int ans=0;
for(int i=1;i<=cnt;i++)
{
if(a[i])
{
x++;
ans=(ans%mod+tot*fastpow(mod-2,x*x)%mod+mod)%mod;
}
}
cout<<ans<<'\n';
}
return 0;
}