8.29考试总结

T1

Description:n(\(10^5\))个点m(\(10^5\))个双向边中有k(\(10^2\))个绿洲,求每个点离最远的绿洲的最短距离

Solution:以每个绿洲为源点,走\(k\)次SPFA(一定不能跑dijsktra会TLE)

My Think:(80分)这一道题可以说是我有史以来出过的最大的锅了,我竟然把输入放在了freopen前面,爆零了(原本能拿80),原本估分是100,以后一定要严格计算时间复杂度,尤其在选择两个可行的算法时,比如:SPFA(\(n\times k\)),dijsktra(\(mlogn\)),揣测出题人意图,这道题,如果使用\(dijsktra\)(\(kmlogn\)=\(10^2\times10^5\times20=2\times10^8\) )怎么卡都卡不过
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int MAXX=100010;
int head[MAXX],ver[MAXX<<1],nxt[MAXX<<1],dis[110][MAXX];
int n,m,kk,tot;
int a[MAXX];
bool vis[110][MAXX];
inline void add(int x,int y){
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
inline void spfa(){
    for(int i=1;i<=kk;++i)
        for(int j=1;j<=n;++j)dis[i][j]=0x3f3f3f3f;
    queue<int>q;
    for(int k=1;k<=kk;++k){
     dis[k][a[k]]=0;
     q.push(a[k]);
     vis[k][a[k]]=1;
     while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[k][x]=0;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i];
            if(dis[k][y]>dis[k][x]+1){
                dis[k][y]=dis[k][x]+1;
                if(!vis[k][y]){
                 q.push(y);
                 vis[k][y]=1;
                }
            }
         }
       }
    } 
}
int main(){
   freopen("oasis.in","r",stdin);
   freopen("oasis.out","w",stdout);
   cin>>n>>m>>kk;
   for(int i=1;i<=kk;++i)scanf("%d",&a[i]);
   for(int i=1;i<=m;++i){
    int x,y;
    scanf("%d%d",&x,&y);
    add(x,y);
    add(y,x);
   }
   spfa();
   for(int i=1;i<=n;++i){
        int maxx=-0x3f3f3f3f;
        for(int j=1;j<=kk;++j)maxx=max(maxx,dis[j][i]);
        printf("%d ",maxx);
   }
   fclose(stdin);
   fclose(stdout);
   return 0;
}
/*
5 7 2
2 3
1 2
1 3
1 4
2 4
3 4
3 5
4 5
*/

T2

Description:给n(\(10^3\)) 的点,和每个点相邻的点的个数,求图的不同方案个数

Solution:~太难了我看不懂题解~

\(dp[i][j]\) 表示有i个1,j个2的方案数
转移:考虑加入一个点(1.加入了一个1点。2.加入了一个2点)
<1>i+1,向剩下的i集合连一条边,我们将这两个抹去变成了\(dp[i-1][j]\),即\(dp[i+1][j]+=i\times dp[i-1][j]\),注意这个与j无关,所以仅仅转移一次,可以在第一层循环写
注释:i+1,不能向j集合连边,因为那样没有意义,j集合少了一个,而i集合多了一个,变成了\(dp[i+1][j]\)集合还是没有变化
<2>j+1,向i集合中的两个点,分别连一条边,我们抹去这两个点(集合i),变成了\(dp[i-2][j]\),即\(dp[i][j+1]+=C_{i}^{2}\times dp[i-2][j]\)
<3>j+1,向j集合中两个点,分别连一条边,j集合中少了两个,而i集合多了两,变成了\(dp[i+2][j-2]\),即\(dp[i][j+1]+=C_{j}^{2}\times dp[i+2][j-2]\)
<4>j+1,向j集合中连一条边,再向i集合中连一条边,j集合少了一个,i集合少了一个又多了一个,变成了\(dp[i-1+1][j-1]\),即\(dp[i][j+1]+=dp[i][j-1]\times i\times j\)
My Think:(30分)D=1找规律,\(n<=10\)打暴力
Code:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXX=2010;
const int p=998244353;
int n,a,b;
long long f[MAXX][MAXX];
long long C(long long x){
    return (x*(x-1)/2)%p;
}
int main(){
  freopen("map.in","r",stdin);
  freopen("map.out","w",stdout);
  scanf("%d",&n);
  for(int i=1;i<=n;++i){
    int d;
    scanf("%d",&d);
    if(d==1)a++;
    else b++;
  }
  f[0][0]=1;
  for(int tot=1;tot<=a+b;++tot){
    f[tot+1][0]=(f[tot+1][0]+f[tot-1][0]*tot%p)%p;//注意边界和long long
    for(int i=0;i<=tot;++i){
        int j=tot-i;
        if(j<0)continue;
        if(i>=2)f[i][j+1]=(f[i][j+1]+f[i-2][j]*C(i)%p)%p;
        if(j>=2)f[i][j+1]=(f[i][j+1]+f[i+2][j-2]*C(j)%p)%p;
        if(i&&j)f[i][j+1]=(f[i][j+1]+f[i][j-1]*i%p*j%p)%p;
    }
  }
  cout<<f[a][b]%p;
  fclose(stdin);
  fclose(stdout);
  return 0;
}
/*
4
2 1 1 2
*/

T3

Description:长度为n($ 2\times 10^5 $ )的序列,m(\(2\times 10^5\))次单点修改,查询每次修改后最小的位置,使该位置的值等于前缀和

Solution:

线段树维护区间sum,max,修该操作:直接线段树单点修改,查询操作:每次查询区间内大于等于前缀和的第一个位置,复杂度(\(M\times logn \times log 10^9\))因为每次sum至少会翻倍,而\(p_i<=10^9\),所以是\(log10^9\)
My Think:(30分)暴力
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXX=200010;
struct node
{
    long long sum;
    int mx;
    node(){
        sum=mx=0;
    }
}t[MAXX<<2];
int n,m;
int a[MAXX];
inline void build(int cur,int l,int r){
    if(l==r){
        t[cur].sum=t[cur].mx=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    if(l<=mid)build(cur<<1,l,mid);
    if(r>mid)build(cur<<1|1,mid+1,r);
    t[cur].sum=t[cur<<1].sum+t[cur<<1|1].sum;
    t[cur].mx=max(t[cur<<1].mx,t[cur<<1|1].mx);
}//ok
inline void update(int cur,int l,int r,int pos,int val){
    if(l==r){
        t[cur].sum=t[cur].mx=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)update(cur<<1,l,mid,pos,val);
    else update(cur<<1|1,mid+1,r,pos,val);
    t[cur].sum=t[cur<<1].sum+t[cur<<1|1].sum;
    t[cur].mx=max(t[cur<<1].mx,t[cur<<1|1].mx);
}
inline long long query_sum(int cur,int l,int r,int L,int R){
    if(L<=l&&R>=r)return t[cur].sum;
    int mid=(l+r)>>1;
    long long ans=0;
    if(L<=mid)ans+=query_sum(cur<<1,l,mid,L,R);
    if(R>mid)ans+=query_sum(cur<<1|1,mid+1,r,L,R);
    return ans;
}
inline int query_pos(int cur,int l,int r,int L,int R,long long val){
    int mid=(l+r)>>1;
    if(L<=l&&R>=r){
       if(t[cur].mx<val)return -1;//本区间是否可行
       if(l==r)return l;//可行返回值
       else if(t[cur<<1].mx>=val)return query_pos(cur<<1,l,mid,L,mid,val);//优先左区间
       else return query_pos(cur<<1|1,mid+1,r,mid+1,R,val);//再右区间
    }
    int ans=-1;
    if(L<=mid)ans=query_pos(cur<<1,l,mid,L,mid,val);
    if(ans!=-1)return ans;
    else if(R>mid)ans=query_pos(cur<<1|1,mid+1,r,mid+1,R,val);
    return ans;
}
int main(){
    freopen("challenge.in","r",stdin);
    freopen("challenge.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=m;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        update(1,1,n,x,y);
        a[x]=y;
        int pos=0;
        int ans=-1;
        long long presum=0;
        while(pos<=n){
          pos=query_pos(1,1,n,pos+1,n,presum);
          if(pos==-1){
            ans=-1;
            break;
          }
          presum=query_sum(1,1,n,1,pos);
          if(presum-a[pos]==a[pos]){
            ans=pos;
            break;
          }
        }
        printf("%d\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
10 7
0 3 1 4 6 2 7 8 10 1
2 5
1 3
9 36
4 10
4 9
1 2
1 0
*/

总结:

估分:160

想法:140(没有认真分析时间复杂度)

实际:60(智障错误,以后一定要使用freopen输入输出样例)

不算智障错误,感觉还不错,暴力打得不错,以后一定要避免智障错误

改正:

1.避免智障错误
2.以后一定要使用freopen输入输出样例
3.常分析时间复杂度
4.板子要熟练

猜你喜欢

转载自www.cnblogs.com/ARTlover/p/9560039.html