day2018.8.26模拟赛总结

版权声明:转载请注明原出处啦(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82079463

T1:

题目大意:给出一个人的每门课的成绩排名,求这个人总成绩的最大排名和最小排名.

开始看的时候想这道题感觉这道题很懵啊,觉得总排名跟各科排名没什么关系啊.

突然如果只要有一门课的成绩比另一个人低,就有可能总成绩比那个人低...

所以代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000;
int n,m,a[N+9],su,sd;
Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++)
    scanf("%d",&a[i]);
}
Abigail work(){
  for (int i=1;i<=n;i++)
    su+=a[i]-1,sd+=m-a[i];
}
Abigail outo(){
  if (sd>=m) printf("1\n");
  else printf("%d\n",m-sd);
  if (su>=m) printf("%d\n",m);
  else printf("%d\n",su+1);
}
int main(){
  freopen("rank.in","r",stdin);
  freopen("rank.out","w",stdout);
  into();
  work();
  outo();
  return 0;
} 

T2:

题目大意:给定一张有向图,每个节点只有一条出边,现在要求每个节点开始的最长链(简单路径)长度,其中所有边的边权都为正数.

感觉这道题跟NOIP2015信息传递很像啊,于是就把环先找出来打上标记,算出每个环的和,然后记忆化搜索就可以了.

考场上还剩半个小时的时候拍出问题也是恐怖.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200000;
struct node{
  int to,v,c,ans;
}d[N+9];
int sum[N+9],n,num,top,t[N+9];
int dfs(int k){
  if (t[k]&&t[k]^top) return 0;
  if (t[k]==top) {
    d[k].c=++num;
    return num;
  }
  t[k]=top;
  int now=dfs(d[k].to);
  if (d[k].c) return 0;
  else {
    d[k].c=now;
    return now;
  }
}
int dfs1(int k){
  if (d[k].ans) return d[k].ans;
  t[k]=1;
  if (d[k].c) {
    d[k].ans=sum[d[k].c];
    return d[k].ans;
  }
  d[k].ans=d[k].v+dfs1(d[k].to);
  return d[k].ans;
}
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&d[i].v);
  for (int i=1;i<=n;i++)
    scanf("%d",&d[i].to);
}
Abigail work(){
  for (int i=1;i<=n;i++)
    if (!t[i]) top++,dfs(i);
  for (int i=1;i<=n;i++)
    sum[d[i].c]+=d[i].v;
  for (int i=1;i<=n;i++)
    t[i]=0;
  for (int i=1;i<=n;i++)
    if (!d[i].ans) dfs1(i);
}
Abigail outo(){
  for (int i=1;i<=n;i++)
    printf("%d\n",d[i].ans);
} 
int main(){
  freopen("travel.in","r",stdin);
  freopen("travel.out","w",stdout);
  into();
  work();
  outo();
  return 0; 
} 

T3:

题目大意:给出一个字符串长度为n,只包含前k个小写字母,现在在加上m个字符(也是前k个小写字母),使得字符串中不同的子序列最多,求最多的子序列的数量,对10^9+7取模.

考场写了个分段拿分,一个是k=1的情况(要算上空串),另一个是5进制压位暴力,然后5进制压位暴力没有乘5...

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const LL mod=1000000007;
const int N=1000000;
LL sum,f[N+9],ans[26];
int n,m,k,e[N+9],p[N+9],top,get[N+9],t;
bool use[10000000];
char c[N+9];
Abigail into(){
  scanf("%d%d",&m,&k);
  scanf("%s",&c);
  n=strlen(c);
}
int power(int a,int b){
  int s=1;
  for (int i=1;i<=b;i++)
    s=s*5;
  return s;
}
void check(){
  int s=0,l=0;
  for (int i=0;i<=(1<<n+m)-1;i++){
    l=0;
    for (int j=0;j<n+m;j++)
      if (1<<j&i) l=l|1<<j;
    if (!use[l]) s++,get[++t]=l,use[l]=1;
  }
  if (s>sum) sum=s;
}
void dfs1(int k){
  if (n+k>n+m){
    check();
    for (int i=1;i<=t;i++)
      use[get[i]]=0;
    return;
  }
  for (int i=0;i<5;i++){
    e[i]=i;
    dfs1(k+1);
  }
}
Abigail work1(){
  for (int i=0;i<n;i++)
    e[i+1]=c[i]-'a';
  dfs1(n+1);
}
Abigail work2(){
  sum=1LL*(n+m+1);
}
Abigail outo(){
  printf("%lld\n",sum);
}
int main(){
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  into();
  if (k==1) work2();
  else if (n<=5&&m<=5&&k<=5) work1();
  outo();
  return 0;
}

正解是一个DP,先来看m=0的情况,这个时候不用增加字符,只要求出子序列个数就可以了.

那么我们设f[i]表示到第i个字符必须包括第i个字符的不同子序列的个数.

那么我们发现若直接用f[i]=\sum_{j=1}^{i-1}f[j]会出现一个问题,就是会有重复,那我们在记录一个last[i]表示跟第i个字符相同的上一个出现的位置,那我们再推的时候减掉一个F[last[i]-1]及之前的就可以了.

也就是说公式变成f[i]=\sum_{j=last[i]}^{i-1}f[j],用前缀和优化就可以了.

但是我们应该在后面加入什么字符呢?

我们设g[i]为f[i]的前缀和数组,那么f[i]=g[i-1]-g[last[i]-1],那么我们可以知道下一次转移的时候我们肯定要让f[i]最大,所以我们要让last[i]-1最小.

那么时间复杂度O((n+m)*26),空间复杂度O(n+m).

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const LL mod=1000000007LL;
const int N=1000000;
const LL INF=1LL<<61;
int n,m,k;
LL f[N*2+9],a[N*2+9],last[27],g[N*2+9];
char c[N*2+9];
Abigail into(){
  scanf("%d%d",&m,&k);
  scanf("%s",c+1);
  n=strlen(c+1);
}
Abigail work(){
  for (int i=1;i<=n;i++)
    a[i]=c[i]-'a'+1LL;
  for (int i=1;i<=n;i++){
    if (last[a[i]]<1) f[i]=(g[i-1]+1)%mod;
    else f[i]=(g[i-1]+mod-g[last[a[i]]-1])%mod;
    g[i]=(f[i]+g[i-1])%mod;      //这里的g[i]是表示f[i]的前缀和-f[last[i]-1]的前缀和 
    last[a[i]]=i;      //这里的last[i]是表示字符i上一次出现的位置 
  }
  for (int i=n+1;i<=n+m;i++){
    LL e=0,mi=INF;
    for (int j=1;j<=k;j++)
      if (mi>last[j]) mi=last[j],e=j;
    a[i]=e;      //找到最小的last[i]-1并加入这个i字符 
    if (last[a[i]]<1) f[i]=(g[i-1]+1)%mod;
    else f[i]=(g[i-1]+mod-g[last[a[i]]-1])%mod;
    g[i]=(f[i]+g[i-1])%mod;
    last[a[i]]=i;
  }
}
Abigail outo(){
  printf("%lld\n",(g[n+m]+1>=mod)?g[n+m]+1-mod:g[n+m]+1);
}
int main(){
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/82079463
今日推荐