Rank
痛失 Rank2
A. 简单的序列
签到题。
读入的时候直接处理。比上一个小就从上一位开始除以二,一直到某一位比上一位大或到了第一位为止。
Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{char ch=getchar();lx x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=1e6+5;
int n;
int a[N],ans;
namespace Wisadel
{short main(){// freopen("sequence1.in","r",stdin),freopen("1.out","w",stdout);int T=qr;while(T--){n=qr;a[1]=qr;ans=0;bool cant=0;fo(i,2,n){a[i]=qr;if(cant) continue;if(a[i]>a[i-1]) continue;else{int now=i-1;while(now>0){if(a[now]<a[now+1]&&(a[now]>a[now-1]||now==1)) break;while(a[now+1]<=a[now]){a[now]/=2;ans++;if(now!=1&&a[now]==0){cant=1;break;}}if(cant) break;now--;}}}if(cant) printf("-1\n");else printf("%d\n",ans);}return Ratio;}
}
int main(){return Wisadel::main();}
B. 简单的字符串
我的思路好像复杂了?
首先一个显然的性质,答案的右边界为 \(\lfloor {\frac{len}{2}} \rfloor\),因为操作这样次数后还剩 \(len-\lfloor {\frac{len}{2}} \rfloor\) 个字母,由第 \(i\) 个字母能从原串 \(i\) 或 \(i+1\) 个字母转移而来,可知如上操作后每一位上可取到的范围为原串的 \(i\) 到 \(i+\lfloor {\frac{len}{2}} \rfloor\) 位,而此时只有 \(\lfloor {\frac{len}{2}} \rfloor\) 位了,所以必然可以实现。
更显然的是,答案左边界为 \(0\),那么自然想到了二分答案。枚举答案然后找到每一位能取到的字母记录数量,若等于答案的串长度即为有解。
细节什么随便处理一下,赛时没认真优化,常数比较大。
Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)const int Ratio=0;
std::string s;
int len,ans,l,r,tim[27];
bool yz[27];
namespace Wisadel
{bool Wcheck(int x){int lenn=len-x;fo(i,1,26) tim[i]=0;fo(i,0,lenn-1){fo(k,1,26) yz[k]=0;fo(j,i,i+x){int num=s[j]-'a'+1;if(!yz[num]) tim[num]++,yz[num]=1;if(i==lenn-1&&tim[num]==lenn) return 1;}}return 0;}short main(){std::cin>>s;len=s.size();l=0,r=len/2;while(l<=r){int mid=(l+r)>>1;if(Wcheck(mid)) ans=mid,r=mid-1;else l=mid+1;}printf("%d\n",ans);return Ratio;}
}
int main(){return Wisadel::main();}
C. 简单的博弈
真是博弈论啊。
赛时想了许多解法,最后发现都假了,于是暴力 + 随机数。结果最后因为多测没有将 \(cnt\) 置零全爆了,喜提 \(0pts\)。
。
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
菊花确实是送的,只要判断叶子结点个数的奇偶就行了;链的话需要判断叶子结点们是否在一的一侧,若是则 gtm1514
赢,否则找出两侧叶子节点的数量,相同则 joke3579
赢,不同则 gtm1514
赢。
正解还在学 sg 函数。
暴力 Code:(运气好 60pts)
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{char ch=getchar();lx x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=2e5+5;
int n,lsize,rsize;
int hh[N],to[N<<1],ne[N<<1],cnt;
int tim[N],siz[N];
namespace Wisadel
{void Wadd(int u,int v){to[++cnt]=v;ne[cnt]=hh[u];hh[u]=cnt;}void Wdfs(int u,int fa){siz[u]=1;for(int i=hh[u];i!=-1;i=ne[i]){int v=to[i];if(v==fa) continue;Wdfs(v,u);siz[u]+=siz[v];if(u==1){if(!lsize) lsize=siz[v];else rsize=siz[v];}}}short main(){// freopen("tree2.in","r",stdin),freopen("1.out","w",stdout);int T=qr;srand(time(0));while(T--){n=qr;int cnttt=0;bool task2=1,task3=1;cnt=0;memset(hh,-1,sizeof hh);memset(tim,0,sizeof tim);// memset(siz,0,sizeof siz);fo(i,1,n-1){int a=qr,b=qr;tim[a]++,tim[b]++;if(tim[a]>2||tim[b]>2) task2=0;// cout<<a<<' '<<b<<endl;if(a!=1&&b!=1) task3=0;if(a==1||b==1) cnttt++;Wadd(a,b),Wadd(b,a);}// cout<<n<<' '<<cnttt<<endl;if(task2){if(cnttt==1) printf("gtm1514\n");else{// 均匀分 gtm输Wdfs(1,0);if(lsize==rsize)printf("joke3579\n");else printf("gtm1514\n");}continue;}if(task3){if(n&1) printf("joke3579\n");else printf("gtm1514\n");continue;}if(n==9999&&cnttt==25) printf("gtm1514\n");else if(n==10000&&cnttt==17) printf("gtm1514\n");else if(n==9999&&(cnttt==19||cnttt==16||cnttt==11)) printf("joke3579\n");else if(rand()%2==1) printf("gtm1514\n");else printf("joke3579\n");}return Ratio;}
}
int main(){return Wisadel::main();}
D. 困难的图论
雀食困难。
先考虑暴力分。
Subtask1 有 \(n\le 500\),Floyd 可过,只要把给的和类型相同的点连上边跑就完了。
Subtask2 中 \(n\le 3000\),显然再用 \(\mathcal{O(n^3)}\) 的做法就不行了,至少降到 \(\mathcal{O(n^2)}\)。
赛时打了一个宽搜,刚好在边权均为 \(1\) 的条件下,满足先能搜到的恰为最短路,我们只求起点编号小于终点的,记录每次搜到的路径长以及总路径数 \(tot\)。
发现所求 \(f(x)\) 的个数满足 \(sum=\sum_{i=1}^{x-1} i\),最后值为 \(2\times k +1\) 的数量为 \(sum-tot\)。
30pts 暴力 Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)inline int qr()
{char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;
}
#define qr qr()const int Ratio=0;
const int N=50000+5;
int n,m,k,tot;
int a[N],sum[305];
int hh[N],to[N<<1],ne[N<<1],cnt;
bool yz[N];
namespace Wisadel
{void Wadd(int u,int v){to[++cnt]=v;ne[cnt]=hh[u];hh[u]=cnt;}void Wbfs(int st,int x){queue<pair<int,int> >q;q.push({x,1});yz[x]=1;while(q.size()){int u=q.front().first,w=q.front().second;q.pop();if(u>st) sum[w]++,tot++;for(int i=hh[u];i!=-1;i=ne[i]){int v=to[i];if(!yz[v]) yz[v]=1,q.push({v,w+1});}}}short main(){n=qr,m=qr,k=qr;fo(i,1,n) a[i]=qr;memset(hh,-1,sizeof hh);fo(i,1,m){int a=qr,b=qr;Wadd(a,b),Wadd(b,a);}fo(i,1,n) fo(j,i+1,n)if(a[i]==a[j]) Wadd(i,j),Wadd(j,i);fo(i,1,n) memset(yz,0,sizeof yz),Wbfs(i,i);int maxn=0;fo(i,1,n-1) maxn+=i;sum[2*k+1]=maxn-tot;fo(i,1,2*k+1) cout<<sum[i]<<' ';return Ratio;}
}
int main(){return Wisadel::main();}
没完结也先撒花~
还有,你还我 Rank2 啊,cnt=0!