• CSP非专业S 2020总结 暨 NOIP2020准备日记



    CSP-S 2020总结

    我实力确实很不够。


    NOIP2020准备日记

    前言

    距离 NOIP2020 还有 20+ 天。

    我的实力还是不够, 从今天开始吧。

    2020.11.8 14:09

    2020.11.8

    啊,由于直到上午都是假期,今天的训练从下午开始。

    补了一场膜你的题。 17:03

    T1

    脑糊一下发现字符的贡献是独立的, 分别考虑每个字符,发现每个字符只可能是 s 中出现次数最多的字符之一。

    T2

    排序不等式, 注意支持负数。

    T3

    分类讨论, 不好。

    枚举大法, 好。

    T4

    暂时不补。


    开车旅行这道题, 以前没做出来主要是细节没写好, 这题其实不难写, 用链表写也才100多行。比较关键的地方不少,被 (x_0) 部分的答案更新卡掉了不少时间, 没有考虑到这个答案更新的逻辑居然不是那么简洁。

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N = 1e5+3, inf=2000000000;
    
    int n, h[N], fi[N], se[N];
    int to[18][N];
    LL sa[18][N], sb[18][N];
    
    int a[N];
      bool cmp(int x,int y) {return h[x]<h[y]; }
    int pr[N], nt[N];
    void gen(int &fas, int &sas, int o, int t)
    {
      if(fas==0 || abs(t-h[o])<abs(t-h[fas]) || (abs(t-h[o])==abs(t-h[fas]) && h[o]<h[fas])) sas=fas, fas=o;
      else if(sas==0 || abs(t-h[o])<abs(t-h[sas]) || (abs(t-h[o])==abs(t-h[sas]) && h[o]<h[sas])) sas=o;
    }
    int dis(int x,int y)
    { return (x&&y) ? abs(h[x]-h[y]) :0;  }
    void prework()
    {
      for(int i=1;i<=n;++i) a[i]=i;
      sort(a+1,a+1+n,cmp);
      for(int i=2;i<=n;++i) pr[a[i]]=a[i-1], nt[a[i-1]]=a[i];
      for(int i=1;i<n;++i)
      {
        int fas=0, sas=0, o;
        if(o=pr[i]) gen(fas,sas,o,h[i]);
        if(o=pr[pr[i]]) gen(fas,sas,o,h[i]);
        if(o=nt[i]) gen(fas,sas,o,h[i]);
        if(o=nt[nt[i]]) gen(fas,sas,o,h[i]);
        fi[i]=fas, se[i]=sas;
        if(pr[i]) nt[pr[i]] = nt[i];
        if(nt[i]) pr[nt[i]] = pr[i];
      }
      
      for(int i=1;i<=n;++i)
      {
        to[0][i] = se[i];
        to[1][i] = fi[se[i]];
        sa[0][i] = sa[1][i] = dis(i,se[i]);
        sb[1][i] = dis(se[i],fi[se[i]]);
      }
      for(int k=2;k<=17;++k)
        for(int i=1;i<=n;++i)
        {
          to[k][i] = to[k-1][to[k-1][i]];
          sa[k][i] = sa[k-1][i] + sa[k-1][to[k-1][i]];
          sb[k][i] = sb[k-1][i] + sb[k-1][to[k-1][i]];
        }
    }
    
    LL A,B;
    void calc(int s,int x)
    {
    //  cout << "# "<<s<<','<<x<<" : ";
      A = B = 0ll;
      for(int k=17;k>=0;--k)
      {
    //    cout << k << ' ' << s << ' '  << sa[k][s]+sb[k][s] << ' ' << A+B << '
    ';
        if(to[k][s] && (A+B+sa[k][s]+sb[k][s]<=x))
        {
          A += sa[k][s], B += sb[k][s];
          s = to[k][s];
        }
      }
    }
    /*
    4 
    2 3 1 4 
    3 
    4 
    1 3 
    2 3 
    3 3 
    4 3
    */
    int main()
    {
      scanf("%d",&n);
      h[0] = -2000000000;
      for(int i=1;i<=n;++i) scanf("%d",&h[i]);
      prework();
    //  cout<<sb[0][2]<<'
    ';
    //   for(int i=1;i<=n;++i) {
    //     cout << fi[i] << ' ' << se[i] << '
    ';
    //     // for(int k=0;k<=2;++k) cout<<to[k][i]<<' ';
    //   }
      int x0;
      scanf("%d", &x0);
      calc(1,x0);
      LL fz=A, fm=B;
      int as=1;
      for(int i=2;i<=n;++i)
      {
        calc(i,x0);
        // cout << A << ' ' << B << " # "<<fz<<' '<<fm<<' ';
        if(!fm)
        {
          if(!B && h[i]>h[as]) fz=A, fm=B, as=i;
          else if(B) fz=A, fm=B, as=i;
        }
        else
        {
          if(!B) continue;
          if(1ll*A*fm < 1ll*fz*B || (1ll*A*fm==1ll*fz*B && h[i]>h[as])) fz=A, fm=B, as=i;
        }
        // cout<<fz<<' '<<fm<<'
    ';
      }
      cout << as << '
    ';
      int m;
      scanf("%d",&m);
      for(int i=1;i<=m;++i)
      {
        int s,x;
        scanf("%d%d",&s,&x);
        calc(s,x);
        cout << A << ' ' << B << '
    ';
      }
      return 0;
    }
    

    chibi之zhan这道题

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N = 1003, mo = 1e9+7;
    int n, m, l, a[N], b[N];
    int f[N][N];
    int t[N];
    inline int lowb(int x) {return x&(-x);  }
    void add(int x, LL v) {for(;x<=n+1;x+=lowb(x)) t[x]=(t[x]+v)%mo;  }
    int ask(int x) {int res=0; for(;x;x-=lowb(x)) res=(res+t[x])%mo;  return res;  }
    
    int main()
    {
      int T;
      scanf("%d", &T);
      for(int id=1;id<=T;++id)
      {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%d",&a[i]), b[i]=a[i];
        sort(b+1,b+1+n);
        for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+n+1,a[i])-b+1;
        a[0]=1;
        // discrete
        for(int i=1;i<=n;++i) f[i][1]=1ll;
        for(int j=2;j<=m;++j)
        {
          memset(t,0,sizeof t);
          for(int i=1;i<=n;++i)
          {
            f[i][j] = ask(a[i]-1);
            add(a[i],f[i][j-1]);
          }
        }
        int ans = 0;
        for(int i=m;i<=n;++i) ans = (ans+f[i][m])%mo;
        printf("Case #%d: %d
    ", id, ans);
      }
      return 0;
    }
    

    今天就写几道简单题放松下身心了, 明天开始要开始认真写题了。(我有一个梦想,那就是一天写10道题) 22:08


    2020.11.9

    今天写下搜索。

    写下简单题熟悉下流程

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,w,c[21];
    int hw[21];
    int ans;
    void dfs(int cur, int cnt)
    {
      if(cnt>=ans) return;
      if(cur==n+1)
      {
        ans = min(ans,cnt);
        return;
      }
      hw[++cnt]=c[cur];
      dfs(cur+1,cnt);
      --cnt;
      for(int i=1;i<=cnt;++i)
      {
        if(hw[i]+c[cur]>w) continue;
        hw[i]+=c[cur];
        dfs(cur+1,cnt);
        hw[i]-=c[cur];
      }
    }
    
    bool cmp(int x,int y) {return x>y; }
    int main()
    {
      scanf("%d%d",&n,&w);
      for(int i=1;i<=n;++i) scanf("%d",&c[i]);
      sort(c+1,c+1+n,cmp);
      ans = n+1;
      dfs(1,1);
      cout << ans;
      return 0;
    }
    

    简单题 ims 2

    #include<bits/stdc++.h>
    using namespace std;
    
    char s[82];
    int sum, cnt[1<<9], lg[1<<9];
    int h[82], l[82], b[82];
    int hs[10], ls[10], bs[10];
    
    int lowb(int x) {return x&(-x); }
    
    int dfs(int now)
    {
      if(now==82) return 1;
      int mx=0, as=10;
      for(int i=1,nas;i<=81;++i)
        if(s[i]=='.' && (nas=cnt[ (hs[h[i]]|ls[l[i]]|bs[b[i]])^((1<<9)-1) ])<as) as=nas, mx=i;
      int S = (hs[h[mx]]|ls[l[mx]]|bs[b[mx]])^((1<<9)-1);
      while(S)
      {
        int i = lg[lowb(S)];
        s[mx] = '0'+i+1;
        hs[h[mx]] |= (1<<i);
        ls[l[mx]] |= (1<<i);
        bs[b[mx]] |= (1<<i);
        if(dfs(now+1)) return 1;
        s[mx] = '.';
        hs[h[mx]] ^= (1<<i);
        ls[l[mx]] ^= (1<<i);
        bs[b[mx]] ^= (1<<i);
        S -= lowb(S);
      }
      return 0;
    }
    
    void init()
    {
      lg[0]=-1;
      for(int i=1;i<(1<<9);++i) 
        cnt[i]=cnt[i>>1]+(i&1),
         lg[i]=lg[i>>1]+1;
      for(int i=1;i<=81;++i)
      {
        h[i] = (i-1)/9+1;
        l[i] = (i-1)%9+1;
        b[i] = (i-1)/27*3 + (l[i]-1)/3 + 1;
        // cout << h[i] << ' ' << l[i] << ' ' << b[i] << '
    ';
      }
    }
    
    int main()
    {
      init();
      
      while(scanf("%s",s+1)==1)
      {
        if(s[1]=='e') break;
        memset(hs,0,sizeof hs);
        memset(ls,0,sizeof ls);
        memset(bs,0,sizeof bs);
        sum = 0;
        for(int i=1;i<=81;++i) if(s[i]!='.') {
          ++sum;
          int v = s[i]-'1';
          hs[h[i]] |= (1<<v);
          ls[l[i]] |= (1<<v);
          bs[b[i]] |= (1<<v);
        }
        if(dfs(sum+1))
        {
          printf("%s
    ",s+1);
        }
      }
      return 0;
    }
    

    拼木棒, 也算简单题吧。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n, a[71], sum, mx;
    int len, nd;
    
    int vis[71];
    bool dfs(int now, int l, int las)
    {
      if(now==nd+1) return true;
      if(l==len) return dfs(now+1,0,1);
        int lfail = 0;
      for(int i=las;i<=n;++i)
        if(!vis[i] && l+a[i]<=len && a[i]!=lfail)
        {
          vis[i]=1;
          if(dfs(now,l+a[i],i+1)) return true;
          vis[i]=0;
          lfail = a[i];
          if(l+a[i]==len || l==0) return false;
        }
      return false;
    }
    
    bool cmp(int x,int y) {return x>y;}
    int main()
    {
      while(scanf("%d",&n)==1 && n)
      {
        sum=0, mx=0;
        for(int i=1;i<=n;++i) scanf("%d",&a[i]), sum+=a[i], mx=max(mx,a[i]);
        sort(a+1,a+1+n,cmp);
        for(len=mx; len<=sum; ++len)
          if(sum%len == 0)
          {
            memset(vis,0,sizeof vis);
            nd = sum/len;
            if(dfs(1,0,1)) break;
          }
        cout << min(sum,len) << '
    ';
      }
      return 0;
    }
    

    生日蛋糕, 挺锻炼毛估估的手段。

    // sum pi R^2 H = N pi  --> sum R^2 H = N
    // let dixiadedongxi sum 2 R H smallest
    #include<bits/stdc++.h>
    using namespace std;
    const int M = 21;
    
    int n,m;
    int ans=1000000000;
    int fs[M], fq[M];
    
    //S是体积, Q是面积
    void dfs(int now, int S, int Q, int pR, int pH)
    {
      if(now==m+1)
      {
        if(S==n) ans=min(ans, Q);
        return;
      }
      if(S+fs[now]>n || Q+fq[now]>=ans) return;
      if(S+(m-now+1)*pH*pR*pH<n) return;
      for(int R=pR-1;R>=m-now+1;--R)
        for(int H=pH-1;H>=m-now+1;--H)
        if(S+R*R*H<=n)
        {
          dfs(now+1, S+R*R*H, Q+2*R*H+(now==1?R*R:0), R, H);
        }
    }
    
    int main()
    {
      cin>>n>>m;
      for(int i=m;i>=1;--i)
        fs[i]=(m-i+1)*(m-i+1)*(m-i+1), fq[i]=2*(m-i+1)*(m-i+1);
      fq[1] += m*m*m;
      dfs(1,0,0,sqrt(n),sqrt(n));
      cout << (ans==1000000000?0:ans);
      return 0;
    }
    

    迭代加深练习

    简单的思想。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 101;
    
    int n,m,a[N];
    
    bool v[N];
    bool dfs(int now)
    {
      if(now > m) return a[m]==n;
      int vis[N] = {0};
      for(int i=1;i<=now-1;++i)
        for(int j=1;j<=now-1;++j)
          if(!vis[a[i]+a[j]] && a[i]+a[j]>a[now-1])
          {
            vis[a[i]+a[j]]=1;
            a[now] = a[i]+a[j];
            if(dfs(now+1)) return true;
          }
      return false;
    }
    
    int main()
    {
      a[1]=1;
      while(scanf("%d",&n)==1 && n)
      {
        if(n==1)
        {
          puts("1");
          continue;
        }
        for(m=2; m<=n; ++m)
          if(dfs(2)) break;
        for(int i=1;i<=m;++i) cout << a[i] << ' ';
        cout << '
    ';
      }
      return 0;
    }
    

    meet in the middle 练习

    巧妙的思想。

    懒了,算了。

    ”手写“堆

    直接用 make_heap 及相关函数, 听人说这些函数和 priority_queue 内部用的是同一套算法, 但是由于 priority_queue 用的是 vector 作容器, 所以看上去就很慢;同时由于这类函数可以用于自定义的数组, 所以可扩展性稍微有点高。

    跑最短路的话堆的大小只需要开 N+M 就行。

    开了 O2 跑最短路两者效率差不多。

    在不开 O2 的情况下比较一下效率:

    //make_heap 比 priority_queue 快了大于 500ms
    //849ms
    #include<bits/stdc++.h>
    
    using namespace std;
    const int N=100003, M=200003;
    
    int n,m,s;
    int ct, hd[N], nt[M+1], vr[M+1], w[M+1];
    void ad(int u,int v,int W) {nt[++ct]=hd[u], hd[u]=ct; vr[ct]=v, w[ct]=W;}
    
    struct node{
    	int id, d;
    };
    bool operator<(node x,node y)
    {
    	return !(x.d<y.d);
    }
    
    int d[N], v[N];
    priority_queue<node>q;
    void Dij()
    {
    	for(int i=1;i<=n;++i) d[i]=2e9;
    	d[s]=0;
    	q.push((node){s,0});
    	while(!q.empty())
    	{
    		int x=q.top().id; q.pop();
    		if(v[x]) continue;
    		v[x]=1;
    		for(int i=hd[x];i;i=nt[i])
    		{
    			int y=vr[i], z=w[i];
    			if(d[y] > d[x]+z)
    			{
    				d[y] = d[x]+z;
    				q.push((node){y,d[y]});
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&s);
    	for(int i=0;i<m;++i)
    	{
    		int u,v,W;
    		scanf("%d%d%d",&u,&v,&W);
    		ad(u,v,W);
    	}
    	Dij();
    	for(int i=1;i<=n;++i) cout << d[i] << ' ';
    	return 0;
    }
    
    
    //373 ms
    #include<bits/stdc++.h>
    
    using namespace std;
    const int N=100003, M=200003;
    
    int n,m,s;
    int ct, hd[N], nt[M+1], vr[M+1], w[M+1];
    void ad(int u,int v,int W) {nt[++ct]=hd[u], hd[u]=ct; vr[ct]=v, w[ct]=W;}
    
    struct node{
    	int id, d;
    };
    bool operator<(node x,node y)
    {
    	return !(x.d<y.d);
    }
    
    int d[N], v[N];
    node q[N*5];
    int tot;
    void Dij()
    {
    	for(int i=1;i<=n;++i) d[i]=2e9;
    	d[s]=0;
    	q[++tot] = (node){s,0};
    	while(tot)
    	{
    		int x=q[1].id;
    		pop_heap(q+1,q+1+tot--);
    		if(v[x]) continue;
    		v[x]=1;
    		for(int i=hd[x];i;i=nt[i])
    		{
    			int y=vr[i], z=w[i];
    			if(d[y] > d[x]+z)
    			{
    				d[y] = d[x]+z;
    				q[++tot] = (node){y,d[y]};
    				push_heap(q+1,q+1+tot);
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&s);
    	for(int i=0;i<m;++i)
    	{
    		int u,v,W;
    		scanf("%d%d%d",&u,&v,&W);
    		ad(u,v,W);
    	}
    	Dij();
    	for(int i=1;i<=n;++i) cout << d[i] << ' ';
    	return 0;
    }
    

    一道简单题,一开始算法假了改了半天。

    // 二分 + 0/1 bfs
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1003, M=10003;
    
    int n,p,k;
    int ct, hd[N], nt[M*2+1], vr[M*2+1], w[M*2+1];
    void ad(int u,int v,int W) {nt[++ct]=hd[u], hd[u]=ct; vr[ct]=v, w[ct]=W; }
    
    int d[N];
    deque<int>q;
    bool chk(int lim)
    {
      for(int i=2;i<=n;++i) d[i]=21474836;
      d[1]=0;
      q.push_back(1);
      
      while(!q.empty())
      {
        int x=q.front(); q.pop_front();
        for(int i=hd[x];i;i=nt[i])
        {
          int y=vr[i], z=(w[i]>lim);
          if(d[y]>d[x]+z)
          {
            d[y]=d[x]+z;
            if(z) q.push_back(y);
            else q.push_front(y);
          }
        }
      }
      return d[n]<=k;
    }
    
    int main()
    {
      int l=0,r=0,mx=0;
      scanf("%d%d%d",&n,&p,&k);
      for(int i=0;i<p;++i)
      {
        int u,v,W;
        scanf("%d%d%d",&u,&v,&W);
        ad(u,v,W), ad(v,u,W);
        mx = max(mx,W);
      }
      r=mx+1;
      while(l!=r)
      {
        int mid = (l+r)>>1;
        if(chk(mid)) r=mid;
        else l=mid+1;
      }
      cout << (l==mx+1?-1:l);
      // cout << mx<<'
    ';
      return 0;
    }
    

    无向图联通性

    桥一定是搜索树中的边, 一个简单环中的边一定都不是桥。

    B城, 在搜索树上统计答案

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+3, M=5e5+3;
    
    int n,m;
    int ct, hd[N], nt[M*2+1], vr[M*2+1];
    void ad(int x,int y) {nt[++ct]=hd[x], hd[x]=ct; vr[ct]=y;  }
    
    long long ans[N];
    
    int rt, cnt, dfn[N], low[N], siz[N];
    bool cut[N];
    void tar(int x)
    {
      dfn[x] = low[x] = ++cnt;
      siz[x] = 1;
      int flg=0, sum=0;
      for(int i=hd[x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!dfn[y])
        {
          tar(y);
          siz[x] += siz[y];
          low[x] = min(low[x],low[y]);
          if(low[y]>=dfn[x])
          {
            ++flg;
            if(flg>1 || x!=rt) cut[x]=true;
            
            sum += siz[y];
            ans[x] += 1ll * siz[y] * (n-siz[y]);
          }
        }
        else low[x] = min(low[x],dfn[y]);
        
      if(cut[x])
        ans[x] += 1ll * (n-sum-1) * (sum+1) + (n-1);
      else
        ans[x] = 2ll*(n-1);
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=0,a,b; i<m; ++i)
      {
        scanf("%d%d",&a,&b);
        ad(a,b), ad(b,a);
      }
      tar(rt=1);
      for(int i=1;i<=n;++i) cout << ans[i] << '
    ';
      return 0;
    }
    

    简单题,感谢出题人放水

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+3, M=2e5+3;
    
    int n,m;
    int ct, hd[2][N], nt[M*4+1], vr[M*4+1];
    void ad(int i,int u,int v) {nt[++ct]=hd[i][u], hd[i][u]=ct; vr[ct]=v; }
    
    int cnt, dfn[N], low[N];
    bool bri[M*2+1];
    void tar(int x,int in_e)
    {
      dfn[x] = low[x] = ++cnt;
      for(int i=hd[0][x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!dfn[y])
        {
          tar(y,i);
          low[x] = min(low[x],low[y]);
          
          if(low[y]>dfn[x]) bri[i]=bri[i^1]=true;
        } else
            if(i != (in_e^1)) low[x]=min(low[x],dfn[y]);
    }
    
    int col[N], ccnt;
    void dfs(int x)
    {
      col[x] = ccnt;
      for(int i=hd[0][x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!col[y] && !bri[i]) dfs(y);
    }
    
    int ans, vis[N];
    
    int dep[N], fa[N];
    void dfs2(int x)
    {
      for(int i=hd[1][x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(y!=fa[x]) dep[y]=dep[x]+1, fa[y]=x, dfs2(y);
    }
    
    int main()
    {
      int id=0;
      while(scanf("%d%d",&n,&m)==2 && n && m)
      {
        printf("Case %d:
    ", ++id);
        ct=1;
        memset(hd,0,sizeof hd);
        memset(dfn,0,sizeof dfn);
        memset(bri,0,sizeof bri);
        ccnt=0;
        memset(col,0,sizeof col);
        for(int i=0,a,b; i<m; ++i)
        {
          scanf("%d%d",&a,&b);
          ad(0,a,b);
          ad(0,b,a);
        }
        tar(1,0);
        for(int i=1;i<=n;++i)
          if(!col[i])
          {
            ++ccnt;
            dfs(i);
          }
        ans = 0;
        int oct=ct;
        for(int i=2;i<=oct;i+=2)
          if(bri[i])
          {
            ++ans;
            ad(1,col[vr[i]],col[vr[i^1]]);
            ad(1,col[vr[i^1]],col[vr[i]]);
          }
        fa[1]=0;
        dfs2(1);
        memset(vis,0,sizeof vis);
        int q;
        scanf("%d",&q);
        while(q--)
        {
          int a,b;
          scanf("%d%d",&a,&b);
          a=col[a], b=col[b];
          if(a==b)
          {
            cout << ans << '
    ';
            continue;
          }
          dep[a]>dep[b] ? a^=b^=a^=b :0;
          while(dep[b]>dep[a]) {
            if(!vis[b]) --ans, vis[b]=1;
            b=fa[b];
          }
          while(a!=b) {
            if(!vis[b]) --ans, vis[b]=1;
            if(!vis[a]) --ans, vis[a]=1;
            b=fa[b], a=fa[a];
          }
          cout << ans << '
    ';
        }
        cout << '
    ';
      }
      return 0;
    }
    

    v-DCC缩点

    void tarjan(int x)
    {
      dfn[x] = low[x] = ++num;
      sta[++top] = x;
      if(x==root && hd[x]==0) { // 孤立点
        dcc[++cnt].push_back(x);
        return;
      }
      int flg=0;
      for(int i=hd[x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!dfn[y])
        {
          tarjan(y);
          low[x] = min(low[x],low[y]);
          if(low[y]>=dfn[x])
          {
            ++flg;
            if(flg>1 || x!=root) cut[x] = true;
            
            ++cnt;
            int z;
            do{
              s = sta[top--];
              dcc[cnt].push_back(z);
            } while(z!=y);
            dcc[cnt].push_back(x);
          }
        }
        else low[x] = min(low[x],dfn[y]);
    }
    

    圆桌骑士,习得了多测的新技能

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1003, M = 1000003;
    
    int n,m;
    int ct, hd[N], nt[M*2+1], vr[M*2+1];
    void ad(int x,int y) {nt[++ct]=hd[x], hd[x]=ct; vr[ct]=y; }
    
    int rt, cnt, dfn[N], low[N];
    vector<int>dcc[N];
    int dcnt;
    int sta[N], tp;
    
    void tar(int x)
    {
      dfn[x] = low[x] = ++cnt;
      if(rt==x && !hd[x])
      {
        dcc[++dcnt].clear();
        dcc[dcnt].push_back(x);
        return;
      }
      sta[++tp] = x;
      for(int i=hd[x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!dfn[y])
        {
          tar(y);
          low[x] = min(low[x],low[y]);
          
          if(low[y]>=dfn[x])
          {
            dcc[++dcnt].clear();
            int z;
            do{
              z=sta[tp--];
              dcc[dcnt].push_back(z);
            } while(z!=y);
            dcc[dcnt].push_back(x);
          }
        }
        else low[x] = min(low[x],dfn[y]);
    }
    
    bool ok[N], vis[N];
    int col[N];
    
    bool dfs(int x)
    {
      for(int i=hd[x],y=vr[i]; i; i=nt[i],y=vr[i])
      {
        if(!ok[y]) continue;
        if(!col[y]) {
          col[y] = 3-col[x];
          if(!dfs(y)) return false;
        } else if(col[x]==col[y]) return false;
      }
      return true;
    }
    
    bool G[N][N];
    
    int main()
    {
      while(scanf("%d%d",&n,&m)==2 && n && m)
      {
        ct=0;
        memset(hd,0,sizeof hd);
        dcnt=0;
        memset(dfn,0,sizeof dfn);
        cnt=0;
        memset(vis,0,sizeof vis);
        memset(col,0,sizeof col);
        tp=0;
        memset(G,0,sizeof G);
        for(int i=0,a,b; i<m; ++i)
        {
          scanf("%d%d",&a,&b);
          G[a][b] = G[b][a] = true;
        }
        for(int i=1;i<=n;++i)
          for(int j=i+1;j<=n;++j)
            if(!G[i][j]) ad(i,j), ad(j,i);
        for(int i=1;i<=n;++i)
          if(!dfn[i]) tar(rt=i);
        int ans = 0;
        for(int i=1;i<=dcnt;++i)
        {
          vector<int>::iterator it;
          for(it=dcc[i].begin(); it!=dcc[i].end(); ++it)
            ok[*it] = true;
          int x = *dcc[i].begin();
          col[x] = 1;
          if(!dfs(x)) {
            for(it=dcc[i].begin(); it!=dcc[i].end(); ++it)
              vis[*it] = true;
          }
          for(it=dcc[i].begin(); it!=dcc[i].end(); ++it)
            ok[*it] = false, col[*it]=0;
        }
        for(int i=1;i<=n;++i) if(vis[i]) ++ans;
        cout << n-ans << '
    ';
      }
      return 0;
    }
    

    令人印象深刻的错误, 由于考虑不周。

    我吹爆 Kosaraju 算法, 短小又方便。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int N=103, M=10003;
    
    int n;
    int ct, hd[2][N], nt[M*2+3], vr[M*2+3];
    void ad(int i,int x,int y) {nt[++ct]=hd[i][x], hd[i][x]=ct; vr[ct]=y; }
    
    int sta[N],tp;
    int vis[N], dcc[N], dcnt;
    
    void dfs1(int x)
    {
      vis[x]=1;
      for(int i=hd[0][x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!vis[y]) dfs1(y);
      sta[++tp]=x;
    }
    
    void dfs2(int x)
    {
      dcc[x] = dcnt;
      for(int i=hd[1][x],y=vr[i]; i; i=nt[i],y=vr[i])
        if(!dcc[y]) dfs2(y);
    }
    
    void kosaraju()
    {
      for(int i=1;i<=n;++i)
        if(!vis[i]) dfs1(i);
      for(int i=tp;i>=1;--i)
        if(!dcc[sta[i]]) ++dcnt, dfs2(sta[i]);
    }
    
    int ideg[N], odeg[N];
    
    int main()
    {
      
      scanf("%d",&n);
      for(int x=1;x<=n;++x)
      {
        int y;
        while(scanf("%d",&y)==1 && y) ad(0,x,y), ad(1,y,x);
      }
      kosaraju();
      if(dcnt==1)
      {
        puts("1");
        puts("0");
        return 0;
      }
      for(int x=1;x<=n;++x)
        for(int i=hd[0][x],y=vr[i]; i; i=nt[i],y=vr[i])
          if(dcc[x]!=dcc[y])
            ++odeg[dcc[x]], ++ideg[dcc[y]];
      int i0_=0, o0_=0;
      for(int i=1;i<=dcnt;++i)
        i0_ += ideg[i]==0,
        o0_ += odeg[i]==0;
      cout << i0_ << '
    ' << max(i0_,o0_);
      return 0;
    }
    

    小结

    这两天就是做了点题,复习了点算法,由于都是以前会的算法,所以写起来不慢。
    效率实在太低啦。
    明天开始要做一场膜你赛, 顺便要开始学新算法啦。
    暂定的算法学习是单调队列优化 DP。
    还有时间的话就学一下更精妙的 DP吧。
    今天晚上剩下的时间就复习下数论吧。

    边界令人印象深刻
    反逻辑错误通常出现于过度劳累之后忘了什么

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N=1000003, M=70003;
    
    int m, p[M], v[M];
    void euler(int n)
    {
      for(int i=2;i<=n;++i)
      {
        if(!v[i]) p[++m] = v[i] = i;
        for(int j=1;j<=m;++j)
        {
          if(p[j]>n/i || p[j]>v[i]) break;
          v[i*p[j]] = p[j];
        }
      }
    }
    
    int n, vis[N];
    int t;
    LL a[N];
    
    int main()
    {
      euler(70000);
      LL L,R;
      while(scanf("%lld%lld",&L,&R)==2)
      {
        memset(vis,0,sizeof vis);
        for(int i=1;i<=m && p[i]<=R;++i)
          for(int j=max((int)ceil(L/p[i]),2); j<=floor(R/p[i]); ++j)
            if(1ll*p[i]*j-L >= 0)
              vis[1ll*p[i]*j - L] = 1;
        if(L==1) vis[0]=1;
        t=0;
        for(LL i=L; i<=R; ++i)
          if(!vis[i-L]) a[++t]=i;
        if(t<2) puts("There are no adjacent primes.");
        else
        {
          LL c1=a[1], c2=a[2], d1=a[1], d2=a[2];
          for(int i=2;i<t;++i)
          {
            if(a[i+1]-a[i] < c2-c1) c2=a[i+1], c1=a[i];
            if(a[i+1]-a[i] > d2-d1) d2=a[i+1], d1=a[i];
          }
          printf("%d,%d are closest, %d,%d are most distant.
    ",c1,c2,d1,d2);
        }
      }
      return 0;
    }
    
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1000003;
    
    int p[N], v[N], m;
    
    int main()
    {
      int n;
      cin >> n;
      for(int i=2;i<=n;++i)
      {
        if(!v[i]) {
          v[i] = p[++m] = i;
          int c=0;
          long long t=1ll*i;
          while(n/t)
          {
            c += n/t;
            t*=i;
          }
          printf("%d %d
    ", i, c);
        }
        for(int j=1;j<=m;++j)
        {
          if(p[j]>v[i] || p[j]>n/i) break;
          v[i*p[j]] = p[j];
        }
      }
      return 0;
    }
    
  • 相关阅读:
    [转]SDRAM中的一些疑惑点
    [转]如何学习小波分析?
    [转]功率谱和频谱的区别、联系
    使用Vim为每一行自动编号
    [转]阿英 Matlab fftshift 详解
    [转]性噪比和相位失真
    神舟笔记本精盾K480N高频噪声消除方法
    Tips:verilog计数分频计算
    vim的列编辑操作
    【题解】 「CTSC2018」暴力写挂 点分治+虚树+树形dp LOJ2553
  • 原文地址:https://www.cnblogs.com/tztqwq/p/13946805.html
Copyright © 2020-2023  润新知