[Contest] Codechef January Challenge 2018

发烧在家躺了一个星期呢…

Rectangle

直接判一下是不是有两对相等的

Maximum Score

倒过来贪心,每次选最大的能选的

K-Concatenation

分三种情况讨论就完了,在一个串呢,在两个串呢,跨越n-2个串

Partition the numbers

先随便分一下,然后枚举小的集合的一个数,把它放到大的集合里,然后判断能不能分匀……感觉是能叉掉的

String Merging

直接DP就好了

Killing Monsters

整体二分,把所有操作和怪兽编号取反,这样就能枚举怪兽的子集来找攻击到它的操作
复杂度很不科学…大概是 O(17×317) ,然后就跑过去了??

Manchery大佬说有trick能降复杂度,挖个坑

A humongous Query

%%%rxdoi
把字符串分两段,设前一段的以0结尾的10子序列个数为f0,同样定义f1
后一段以0开始的10子序列个数为g0,同样定义g1

那么 x=f0g1+f1g0 ,化一下得到 g1=xf1g0f0

枚举所有可行的g0,然后查一下表就好了…
这样枚举数就不容易被卡了,也可能就是很小??

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <vector>

using namespace std;

typedef unsigned int U;
typedef pair<int,int> par;

char a[40];
int t,n,cnt,cou[1<<16|10];
map<par,int> M;
int v[1<<16|10];

inline int count(U S){
  return cou[S>>16]+cou[S&65535];
}

int gcd(int x,int y){
  return y?gcd(y,x%y):x;
}

int main(){
  scanf("%d",&t);
  for(int i=1;i<(1<<16);i++) cou[i]=cou[i>>1]+(i&1);
  while(t--){
    M.clear(); cnt=0; int x,ans=33; U S=0;
    scanf("%s%d",a+1,&x); n=strlen(a+1); x++;
    int m1=n/2,m2=n-m1;
    for(int i=1;i<=n;i++) S=S*2+a[i]-'0';
    for(int i=0;i<(1<<m2);i++){
      if(i&1) continue;
      int g0=1,g1=0;
      for(int j=1;j<m2;j++)
    if(i>>j&1) g1+=g0; else g0+=g1+1;
      g1++;
      if(!M.count(par(g0,g1)))
    M[par(g0,g1)]=count(i^(S&((1<<m2)-1)));
      else
    M[par(g0,g1)]=min(M[par(g0,g1)],count(i^(S&((1<<m2)-1))));
    }
    for(int i=0;i<(1<<m1);i++){
      if(!(i>>(m1-1)&1)) continue;
      int f1=1,f0=0;
      for(int j=m1-2;~j;j--)
    if(i>>j&1) f1+=f0+1; else f0+=f1;
      f0++;
      for(int g1=0;g1*f0<=x;g1++){
    if((x-g1*f0)%f1) continue;
    int g0,d=f1/gcd(f1,f0);
    while(1LL*g1*f0<=x){
      g0=(x-g1*f0)/f1;
      if(M.count(par(g0,g1)))
        ans=min(ans,M[par(g0,g1)]+count(i^(S>>m2)));
      g1+=d;
    }
      }
    }
    if(ans>32) puts("NO");
    else printf("YES\n%d\n",ans);
  }
  return 0;
}
Killjee and k-th letter

为了这题重新学了一遍后缀自动机,感觉之前都白学了
建出后缀树(我使用后缀自动机建的)
那么每个节点就是一些子串的集合,那么子串大小排序就相当于后缀树的dfs序

在dfs序上二分就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long ll;

const int N=500010;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void read(ll &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void read(char *x){
  char c=nc(); int l=0;
  for(;c>'z'||c<'a';c=nc());for(;c>='a'&&c<='z';x[++l]=c,c=nc());
}

int n,q;
char a[N];

namespace SAM{
  int p,cnt,nxt[N][26],fail[N],len[N],pos[N],val[N];

  inline void extend(int x,int ps){
    x-='a'; int np=++cnt; pos[np]=ps;
    len[np]=len[p]+1; val[np]=1;
    while(p && !nxt[p][x]) nxt[p][x]=np,p=fail[p];
    if(!p) fail[np]=1;
    else{
      int q=nxt[p][x];
      if(len[q]==len[p]+1) fail[np]=q;
      else{
    int nq=++cnt; len[nq]=len[p]+1;
    memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
    fail[nq]=fail[q]; fail[q]=fail[np]=nq; pos[nq]=pos[q];
    while(p && nxt[p][x]==q) nxt[p][x]=nq,p=fail[p];
      }
    }
    p=np;
  }

  int t[N],id[N];

  inline void Pre(){
    for(int i=1;i<=cnt;i++) t[len[i]]++;
    for(int i=1;i<=cnt;i++) t[i]+=t[i-1];
    for(int i=1;i<=cnt;i++) id[t[len[i]]--]=i;

    for(int i=cnt;i;i--)
      val[fail[id[i]]]+=val[id[i]];
  }
}

namespace ST{
  int nxt[N][26],val[N],len[N],pos[N],fa[N];
  int lst[N],t;
  ll pre[N];

  void dfs(int x){
    for(int i=0;i<26;i++)
      if(nxt[x][i]){
    lst[++t]=nxt[x][i];
    dfs(nxt[x][i]);
      }
  }

  inline ll calc(int A,int B){
    return 1LL*(A+B)*(B-A+1)/2;
  }

  void Pre(){
    dfs(1);
    for(int p=1;p<=t;p++){
      int i=lst[p];
      pre[p]=pre[p-1]+calc(len[fa[i]]+1,len[i])*val[i];
    }
  }

  inline char Query(ll x){
    int l=1,r=t,mid,res=1;
    while(l<=r) pre[mid=l+r>>1]<x?l=mid+1:r=(res=mid)-1;
    x-=pre[res-1]; res=lst[res];
    int L=len[fa[res]]+1,R=len[res],ret=len[fa[res]]+1;
    while(L<=R) calc(len[fa[res]]+1,mid=(L+R>>1))*val[res]<x?L=mid+1:R=(ret=mid)-1;
    if(ret>len[fa[res]]+1) x-=calc(len[fa[res]]+1,ret-1)*val[res]; x=(x-1)%ret+1;
    return a[pos[res]+x-1];
  }
}

inline void Build(){
  using namespace SAM;
  for(int i=2;i<=cnt;i++){
    ST::pos[i]=pos[i];
    ST::len[i]=len[i];
    ST::val[i]=val[i];
    ST::fa[i]=fail[i];
    ST::nxt[fail[i]][a[pos[i]+len[fail[i]]]-'a']=i;
  }
}

inline ll mul(ll x,ll y,ll P){
  ll ret=0; x%=P; y%=P;
  for(;y;y>>=1,x=(x+x)%P) if(y&1) ret=(ret+x)%P;
  return ret;
}

int main(){
  read(a); n=strlen(a+1);
  SAM::cnt=SAM::p=1;
  for(int i=n;i;i--) SAM::extend(a[i],i);
  SAM::Pre(); Build(); ST::Pre();
  ll lst=0;
  read(q);
  ll Q,M;
  while(q--){
    read(Q); read(M);
    Q=mul(Q,lst,M)+1;
    char c=ST::Query(Q);
    putchar(c); putchar('\n');
    lst+=c;
  }
  return 0;
}
Simplify the Square Root

二分加杜教筛…瞎卡常加上CC随机评测的机制就这样卡过去了…
代码不贴了,丑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值