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 << '\n';
    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]<<'\n';
//   for(int i=1;i<=n;++i) {
//     cout << fi[i] << ' ' << se[i] << '\n';
//     // 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<<'\n';
  }
  cout << as << '\n';
  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 << '\n';
  }
  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\n", 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;
}

简单题 \tims 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] << '\n';
  }
}

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\n",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) << '\n';
  }
  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 << '\n';
  }
  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<<'\n';
  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] << '\n';
  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:\n", ++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 << '\n';
        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 << '\n';
    }
    cout << '\n';
  }
  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 << '\n';
  }
  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_ << '\n' << 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.\n",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\n", 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;
}
posted @ 2020-11-09 08:28  xwmwr  阅读(264)  评论(0编辑  收藏  举报