20220812模拟赛总结
作者:互联网
今天抽出一点时间写总结,最近真的超级忙.....下午要补昨天咕咕的补题
大概是我暑假唯一的博客吧....
最近实力漂浮不定,感觉自己应该再成熟一点,不要受太多外界因素干扰
个人成绩
分数: 300/300
排名:1(算上时间的排名:2)
比赛评价
简单。
别急,确实简单,我没有任何夸自己的意思,不要 mod 我,想一想,跟昨天比,这场比赛是不是相对简单?
我个人更倾向于这几次都没考好,教练给的一个信心赛/摸底赛
比赛过程
T1感觉在哪里见过,一眼二分,但是没有好好看题,以为可以自己安排顺序。
往背包上想,感觉会寄,所以打了一个假贪心
所以我的判断函数是这样的....
bool pd(long long x)
{
memset(b,0,sizeof(b));
int k=1;
for(int i=1;i<=n;i++) {
if(b[k]+a[i]>t)
{
k++;
}
if(k==x+1)return 0;
b[k]+=a[i];
}
return 1;
}
那还不如不二分呢,感觉自己是个弱智
这个时候czn大佬表示做完了,Orz
然后做T2,一眼前缀和,切了
然后做T3,显然是递归,但我死活不过样例
然后换了一种表达,A了自己造的所有数据
造化弄人啊...
T1发现是规定顺序,那就好办了,优先队列即可
然后调试了半天,发现没有清空,加上就没问题了
然后向教练确认AK....
开始写总结
题目解析
T1
二分舞台数,然后利用优先队列模拟奶牛上下台
每次提取一个舞台上的奶牛的下台时间的最小值,再把下一个奶牛的下台时间加入优先队列
判断函数复杂度\(O(n\log n)\),二分复杂度\(O(\log n)\),整体复杂度\(O(n\log^2 n)\)
#include <bits/stdc++.h>
using namespace std;
unsigned long long n,t,a[10000005],l,r,ans;
priority_queue<unsigned long long,vector<unsigned long long>,greater<unsigned long long> >wt;//迪茵大舞台,有牛你就来
bool pd(unsigned long long x)
{
while(!wt.empty())wt.pop();
unsigned long long tm=0;
for(unsigned long long i=1;i<=x;i++)
{
wt.push(a[i]);
tm=max(tm,a[i]);
}
for(unsigned long long i=x+1;i<=n;i++)
{
unsigned long long mn=wt.top();
wt.pop();
wt.push(a[i]+mn);
tm=max(tm,a[i]+mn);
if(tm>t)return 0;
}
if(tm>t)
{
return 0;
}
return 1;
}
int main()
{
cin>>n>>t;
for(unsigned long long i=1;i<=n;i++)
{
cin>>a[i];
}
l=1;r=n;
while(l<=r)
{
unsigned long long mid=(l+r)>>1;
if(pd(mid))
{
r=mid-1;
ans=mid;
}
else
{
l=mid+1;
}
}
cout<<ans;
}
T2
枚举变换的点,变换前手势,变换后手势三样东西,注意可以不变换
然后求出两个区间的胜场数,这个用前缀和统计即可
注意其实不需要搞清楚谁能打败谁,不如这样想:
我枚举的是一个可以打败xx手势的手势,这样用前缀和统计xx手势的数量就行
\(O(n)\)
#include<bits/stdc++.h>
using namespace std;
char c;
long long n,p[1000005],h[1000005],s[1000005],ans;
int main()
{
cin>>n;
for(long long i=1;i<=n;i++)
{
cin>>c;
p[i]=p[i-1];
h[i]=h[i-1];
s[i]=s[i-1];
if(c=='P')
{
p[i]++;
}
if(c=='H')
{
h[i]++;
}
if(c=='S')
{
s[i]++;
}//统计手势
}
for(long long i=1;i<=n;i++)//枚举变换点(在i的右边),不变换可以理解为在n的右边
{
long long px=max(p[i]+s[n]-s[i],p[i]+h[n]-h[i]);//使用可以打败p的手势,和变换后的两种情况
long long hx=max(h[i]+p[n]-p[i],h[i]+s[n]-s[i]);//使用可以打败h的手势,和变换后的两种情况
long long sx=max(s[i]+p[n]-p[i],s[i]+h[n]-h[i]);//使用可以打败s的手势,和变换后的两种情况
ans=max(ans,max(px,max(hx,sx)));//统计最大值
}
cout<<ans<<endl;
}
T3
设\(dg_{x,y}\)为变换\(x\)次后字符串的第\(y\)项,可以递归解决
\[\begin{cases} dg_{0,y}=s_y\\ dg_{x,y}=dg_{x-1,y}(x>0,y\leq 2^{x-1}n)\\ dg_{x,y}=dg_{x-1,2^{x-1}n}(x>0,y= 2^{x-1}n+1)\\ dg_{x,y}=dg_{x-1,y-2^{x-1}n-1}(x>0,y> 2^{x-1}n+1) \end{cases} \]第一个式子不解释
第二个式子相当于两者都有的公共前缀部分,所以一样
第三个式子是第\(x\)次变换多出来的字符串的第一项,一位循环移位,所以相当于原来的最后一位
第四个式子就是第\(x\)次变换多出来的字符串(除了第一项),和前面的一样,对齐即可
时间复杂度可以做到\(O(\log n)\),我很懒,我的做法是\(O(\log^2 n)\)的
#include <bits/stdc++.h>
using namespace std;
string s;
long long n, k, t = 1, cnt = 0, pw[65];
char dg(long long k, long long x) {
if (k == 0)
return s[x - 1];
long long len = pw[k] * n;
if (x <= len / 2)
return dg(k - 1, x);
if (x == len / 2 + 1)
return dg(k - 1, len / 2);
return dg(k - 1, x - len / 2 - 1);
}
int main() {
pw[0] = 1;
for (int i = 1; i <= 64; i++) pw[i] = pw[i - 1] * 2;
cin >> s >> k;
n = s.size();
while (t * n <= k) t *= 2, cnt++;
cout << dg(cnt, k);
}
在最后
其实我的代码很累赘,大家理解思路,不要照着打
结果第一是YWJ?CZN后来又交了一次
标签:总结,return,log,变换,dg,unsigned,long,20220812,模拟 来源: https://www.cnblogs.com/I-am-joker/p/20220812contect.html