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;
}