【真是一次失败的经历呢蒟蒻又垫底了】
T1
【论蒟蒻是怎么拿100分的规律写70分的暴力期望得分90实际得分50的】
小结
- 代码的实现有问题。这道题没有对拍结果成功狗带。这次的策略本来没有毛病(就算打不出正解也可以得90分)
- 怎么把正解想出来【虽然没人指望我想出正解】。
这属于上一个问题的进阶了。以这道题举例,我离想出正解还差哪些条件呢?
宏观分析的毛病:没有考虑清楚就动笔。找出了规律却没有明确怎么用才好,因为时间不多了抱着写一点赚一点的心态开始敲键盘。
细节就是:卡在了dep上,觉得不用dep没办法求公共祖先。经谢大佬点拨才知道就跳序号大的反正它们的公共祖先比它们的序号都小。不会出现跳越界的情况。
注意
最开始r的边界定小了导致无限循环
ll getfa(ll x)
{
if(x==1) return 1;
int l=0,r=60;
while(l<r-1){
int mid=(l+r)>>1;
if(f[mid]<x) l=mid;
else r=mid;
}
//f[r-1]+1<=x<=f[r]
return x-f[l];
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int N=1e6;
ll f[N+5],fa[N+5];
ll getfa(ll x)
{
if(x==1) return 1;
int l=0,r=60;
while(l<r-1){
int mid=(l+r)>>1;
if(f[mid]<x) l=mid;
else r=mid;
}
//f[r-1]+1<=x<=f[r]
return x-f[l];
}
ll lca(ll a,ll b)
{
while(a!=b){
if(a<b) swap(a,b);
a=getfa(a);
}
return a;
}
int main()
{
freopen("fibonacci.in","r",stdin);
freopen("fibonacci.out","w",stdout);
int m;
scanf("%d",&m);
f[1]=1,f[0]=1;
for(int i=2;i<=60;i++) f[i]=f[i-1]+f[i-2];
for(int i=1;i<=m;i++){
ll a,b;
scanf("%I64d%I64d",&a,&b);
printf("%I64d\n",lca(a,b));
}
return 0;
}
T2
【本题得分45,比暴力40多5分蒟蒻是不是该庆祝一下呢】
小结
回忆一下做这道题时的思路……大概是想一想线段树怎么做想不出来好吧开始疯狂数据分治。可惜数据分治最后的效果不大,看来还是时间复杂度没有分析清楚。
这道题的正解用到了一个关键的知识点【二分】,知道标答时感觉”啊竟然这么容易?“(可就是没想到)
注意
之后调题还是WA几次主要是二分边界的原因。
就是这里调了好久
while(l<r-1){
mid=(l+r)>>1;
//if(vec[c][mid]==pos) break;
if(vec[c][mid]<pos) l=mid;
else r=mid;
}
总之这是一个及其不靠谱的语句,以后不要乱用
//if(vec[c][mid]==pos) break;
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=3e5+2;
int a[N];
vector<int> vec[N];
int L(int x,int col)//找到大于等于x大的第一个下标
{
int l=-1,r=vec[col].size();
while(l<r-1){
int mid=(l+r)>>1;
if(vec[col][mid]<x) l=mid;//(l,
else r=mid;
}
return r;
}
int R(int pos,int col)
{
int l=-1,r=vec[col].size();
while(l<r-1){
int mid=(l+r)>>1;
if(vec[col][mid]<=pos) l=mid; //[l,
else r=mid;
}
return l;
}
void change(int c,int pos,int to)
{
int l=-1,r=vec[c].size(),mid;
while(l<r-1){
mid=(l+r)>>1;
//if(vec[c][mid]==pos) break;
if(vec[c][mid]<pos) l=mid;
else r=mid;
}
vec[c][r]=to;
}
int main()
{
//freopen("color.in","r",stdin);
//freopen("color.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
vec[a[i]].push_back(i);
}
int cnt=0;
while(m--){
int opt;
scanf("%d",&opt);
if(opt==1){
++cnt;
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
if(vec[c].size())
printf("%d\n",R(r,c)-L(l,c)+1);
else printf("0\n");
}
if(opt==2){
int x;
scanf("%d",&x);
change(a[x],x,x+1);
change(a[x+1],x+1,x);
swap(a[x],a[x+1]);
}
}
return 0;
}
T3
小结
就不多评价在考场上对T3的表现了因为这道题爆零了,没调出来反而浪费了调T1的时间。
1、 前面的题调太久,做题的时候不够专注且没想好就动笔耽误了时间。
2、没有正确的预判,想了一个暴力就开始打,打完发现是错的。
解法
1。 K==1 还是比较好想的略
2。 K==2 用到了并查集,思想和NOI2013关押罪犯有点类似。分成两组建一个反集合。
【最后只得了84分调到了21:30蒟蒻我真的尽力了】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int K,MAX,M,n;
int a[131072+5],s[131072+5];
int fa[131072*2+5], exi[131072+5];
int getfa(int x)
{
return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
void merge(int a,int b)
{
int pa=getfa(a),pb=getfa(b);
fa[pa]=pb;
}
bool check(int x)
{
if(K==1){
for(int i=sqrt(x);i*i<=MAX+x;i++)
if(i*i>=x)
if(exi[i*i-x]) return 0;
return 1;
}
if(K==2){
int thi=0;bool sam=0;
for(int i=sqrt(x);i*i<=MAX+x;i++)
if(i*i>=x)
if(exi[i*i-x]) {
thi++;
if(i*i-x==x) {
sam=1;continue;
}
merge(x,i*i-x+M);
merge(x+M,i*i-x);
if(getfa(i*i-x+M)==getfa(i*i-x)) return 0;
}
if((sam&&thi>1)||(sam&&exi[x]>=2))
return 0;//出现了2*x=i*i且之前x出现过且还有另一数与x为敌
return 1;
}
}
int main()
{
freopen("division.in","r",stdin);
freopen("division.out","w",stdout);
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
M=max(a[i],M);
}
if(K==1){
int tot=0;
for(int i=n;i>=1;i--){
if(!check(a[i])){
// printf("i:%d %d\n",i,a[i]);
s[++tot]=i;
MAX=0;
memset(exi,0,sizeof(exi));
}
//else
MAX=max(MAX,a[i]);
exi[a[i]]++;
}
printf("%d\n",tot+1);
for(int i=tot;i>=1;i--)
printf("%d ",s[i]);
printf("\n");
}
if(K==2){
int tot=0;s[0]=n;
for(int i=1;i<=2*M;i++) fa[i]=i;
for(int i=n;i>=1;i--){
if(!check(a[i])){//新分组
s[++tot]=i;
MAX=0;
memset(exi,0,sizeof(exi));
for(int j=s[tot];j<=s[tot-1];j++){
fa[a[j]]=a[j];fa[a[j]+n]=a[j]+n;
}
}
// else
MAX=max(MAX,a[i]);
exi[a[i]]++;
}
printf("%d\n",tot+1);
for(int i=tot;i>=1;i--)
printf("%d ",s[i]);
printf("\n");
}
return 0;
}
最后总结:
这次考试还是T1出的问题最大,如果T1过了T2的分数加起来也勉强可看。进步空间嘛就是希望可以更快一点【注意力再集中一点】,所以嘛,【验证代码】是很重要的。
其实今天因为这个还是挺丧的,有点怕明天再垫底【安慰自己*1】