17.9.29
- 上午
- 模拟考试
- Prob 1(AC).水题。
- Prob 2(WA).类似紫书P269例题9-3(旅行),多了一个条件: 两条路必须分别经过两个给定的点。
一个经典的DP转移 dp[i][j]—>dp[max(i,j)+1][j]和dp[i][max(i,j)+1]
此转移用于两条路跑完所有点。
对于新添加的条件,只需在转移时让一个点只出现在状态的第一维,让另一个点只出现在状态的第二维
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> using namespace std; struct point{ int x,y; }p[1010]; double dp[1010][1010],d1,d2; int n,a,b; double dis(int i,int j){ return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)); } int main(){ freopen("paths.in","r",stdin); freopen("paths.out","w",stdout); scanf("%d%d%d",&n,&a,&b); a++; b++; for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); p[n+1]=p[n]; for(int i=1;i<=n+2;i++) for(int j=1;j<=n+2;j++) dp[i][j]=1e9; dp[1][1]=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(i==j&&i!=1) continue; int k=max(i,j)+1; if(k==n+1){ if(i==n) dp[i][k]=min(dp[i][k],dp[i][j]+dis(j,k)); else dp[k][j]=min(dp[k][j],dp[i][j]+dis(i,k)); } else if(k==a) dp[k][j]=min(dp[k][j],dp[i][j]+dis(i,k)); else if(k==b) dp[i][k]=min(dp[i][k],dp[i][j]+dis(j,k)); else dp[i][k]=min(dp[i][k],dp[i][j]+dis(j,k)), dp[k][j]=min(dp[k][j],dp[i][j]+dis(i,k)); } printf("%.2lf",min(dp[n][n+1],dp[n+1][n])); return 0; }
- Prob 3(WA 3个点).线段树维护,注意细节啊 .
- 模拟考试
- 下午
- 迷了很久,很绝望
- 入门OJ 3道题
- 入门OJ 2028 [Noip模拟题]gcd区间
可以暴力求出 f[i][j] 表示i-j区间的GCD
...
打了一个RMQ,练练手代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 1005 using namespace std; int mi[1005]; int val[1005][12]; int gcd(int a,int b){ while(a^=b^=a^=b%=a); return b; } int n,m; int main(){ scanf("%d%d",&n,&m);mi[1]=0; for(int i=2;i<=1001;i++) mi[i]=mi[i>>1]+1; for(int i=1;i<=n;i++) scanf("%d",&val[i][0]); for(int j=1;(1<<j)<=n;j++) for(int i=(1<<j);i<=n;i++) val[i][j]=gcd(val[i-(1<<(j-1))][j-1],val[i][j-1]); for(int i=1,l,r,k,ans;i<=m;i++){ scanf("%d%d",&l,&r); k=mi[r-l+1]; ans=gcd(val[l+(1<<k)-1][k],val[r][k]); printf("%d\n",ans); } return 0; }
- 入门OJ 2029: [Noip模拟题]数列
矩阵幂优化线性递推
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int mod=1000000007; struct maxtrix{ int r,c; int val[5][5]; maxtrix(){ r=c=0; memset(val,0,sizeof(val)); } void identity(int l){ r=c=l; for(int i=1;i<=l;i++) val[i][i]=1; } maxtrix operator * (maxtrix const b){ // c==b.r maxtrix now; now.r=r; now.c=b.c; for(int i=1;i<=r;i++) for(int j=1;j<=b.c;j++) for(int k=1;k<=c;k++) now.val[i][j]=(1ll*now.val[i][j]+1ll*val[i][k]*b.val[k][j])%mod; return now; } maxtrix operator ^ (int b){ maxtrix base,now; base=*this; now.identity(this->r); while(b){ if(b&1) now=now*base; base=base*base; b>>=1; } return now; } }g,d; int T,n; int main(){ scanf("%d",&T); while(T--){ d.r=1;d.c=3; d.val[1][1]=d.val[1][2]=d.val[1][3]=1; scanf("%d",&n); if(n<=3) printf("%d\n",d.val[1][n]); else{ g.r=g.c=3; g.val[1][1]=g.val[1][2]=g.val[2][2]=g.val[2][3]=g.val[3][1]=0; g.val[1][3]=g.val[2][1]=g.val[3][2]=g.val[3][3]=1; g=g^(n-3); d=d*g; printf("%d\n",d.val[1][3]); } } return 0; }
- 入门OJ 2030 [Noip模拟题]高级打字机
弱弱版:
因为不会撤销撤销操作,维护一个栈就好了。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char s[100005],com; int n,x,top; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf(" %c",&com); if(com=='T') scanf(" %c",&s[++top]); else if(com=='U') scanf("%d",&x),top-=x; else scanf("%d",&x),printf("%c\n",s[x]); } return 0; }
强强版:
主席树比较方便,每次操作之后都对应一颗区间线段树,
形成主席树。
undo时直接回到前j个历史版本即可
代码:(学习大米饼大佬的,直接贴上了)
#include<stdio.h> #include<cstring> #define go(i,a,b) for(int i=a;i<=b;i++) const int N=100003; struct Chair_Man_Tree{int l,r,word;}t[N*10]; int q,Root[N],sz,rig[N],mid; void insert(int& u,int L,int R,int pos,char w){ t[++sz]=t[u];u=sz;if(L==R){t[u].word=w;return;}mid=L+R>>1; pos>mid?insert(t[u].r,mid+1,R,pos,w):insert(t[u].l,L,mid,pos,w); } void find(int u,int L,int R,int pos){ if(L==R){printf("%c\n",t[u].word);return;}mid=L+R>>1; pos>mid?find(t[u].r,mid+1,R,pos):find(t[u].l,L,mid,pos); } int main(){ scanf("%d",&q); int now=0,i=0; go(I,1,q){ char c1,c2;int j;scanf(" %c",&c1); if(c1=='T')i++,scanf(" %c",&c2),Root[i]=Root[i-1],insert(Root[i],1,N,++now,c2),rig[i]=now; if(c1=='U')i++,scanf("%d",&j),j=i-j-1,Root[i]=Root[j],now=rig[i]=rig[j]; if(c1=='Q')scanf("%d",&j),find(Root[i],1,N,j); } return 0; }//Paul_Guderian
- 入门OJ 2028 [Noip模拟题]gcd区间
- 晚上
- 入门OJ 3道题
- 入门OJ 2031 [Noip模拟题]无线通讯网贪心:用"卫星"去填补两个距离大的村庄
(最小生成树,kruskal算法),排序所有边,
从小到大枚举边,去联通村庄,直到连通块数等于卫星线路数,
则此时枚举的边为答案。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct point{ int x,y; }p[505]; struct edge{ int u,v; double val; bool operator < (const edge &rtm) const{ return val<rtm.val; } }e[505*505]; int fa[505]; int n,m,k,ent; double dis(int i,int j){ return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)); } int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } int main(){ scanf("%d%d",&k,&n); for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y),fa[i]=i,m++; for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++) e[++ent]=(edge){i,j,dis(i,j)}; sort(e+1,e+ent+1); for(int i=1,fu,fv;i<=ent;i++){ fu=find(e[i].u); fv=find(e[i].v); if(fu==fv) continue; fa[fv]=fu; m--; if(k==m){ printf("%.2lf",e[i].val); break; } } return 0; }
- 入门OJ 2031 [Noip模拟题]无线通讯网贪心:用"卫星"去填补两个距离大的村庄
- 入门OJ 2033 [Noip模拟题]小K的农场
差分约束
列出不等式,化成最短路的dis定义表达:
每个点的距离都小于等于能到它的点的距离+边权。
1:(a,b,-c).
2:(b,a,c).
3:(a,b,0),(b,a,0)
spfa判负环,存在负环则表明无解又学习了一下dfs版的spfa判负环(0 MS),比用优先队列优化后的bfs版(3100MS+)(这么慢,写错了么,没发现啊)快得多
(可能是数据原因吧)代码:
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #define node(a,b) (node){a,b} using namespace std; struct edge{ int to,val,next; }e[10005*3]; struct node{ int id,val; bool operator <(const node &rtm) const{ return val>rtm.val; } }; int dis[10005],chg[10005],head[10005]; bool inq[10005],fg; int n,m,ent=1; void add(int u,int v,int w){ e[ent]=(edge){v,w,head[u]}; head[u]=ent++; } bool BFS_spfa(){ priority_queue<node> q; node u; for(int i=1;i<=n;i++) q.push(node(i,0)),inq[i]=1; while(!q.empty()){ u=q.top(); q.pop(); inq[u.id]=0; for(int i=head[u.id];i;i=e[i].next){ int v=e[i].to; if(dis[v]>dis[u.id]+e[i].val){ dis[v]=dis[u.id]+e[i].val; if(++chg[v]>=n) return 0; if(inq[v]) continue; q.push(node(v,dis[v])); inq[v]=1; } } } return 1; } void dfs(int u){ if(fg)return; inq[u]=1; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(dis[v]>dis[u]+e[i].val){ if(inq[v]){fg=1;return;} dis[v]=dis[u]+e[i].val; dfs(v); } } inq[u]=0; } bool DFS_spfa(){ fg=0; for(int i=1;i<=n;i++) { dfs(i); if(fg) return 0; } return 1; } int main(){ scanf("%d%d",&n,&m); for(int i=1,a,b,c,d;i<=m;i++){ scanf("%d",&a); if(a==1) scanf("%d%d%d",&b,&c,&d),add(b,c,-d); if(a==2) scanf("%d%d%d",&b,&c,&d),add(c,b,d); if(a==3) scanf("%d%d",&b,&c),add(b,c,0),add(c,b,0); } if(/*BFS_spfa()*/DFS_spfa()) printf("Yes"); else printf("No"); return 0; }
- 入门OJ 3道题
- 入门OJ 2034 [Noip模拟题]斐波那契数列
又是一个水水题。
矩阵幂优化线性递推
特判(n<=2) 输出1
会有n<2的输入...(坑,说好的n>=2呢)
还有,n为long long型代码:
#include<cstdio> #include<cstring> #include<iostream> #define ll long long using namespace std; const int mod=1000000007; struct maxtrix{ int r,c; int val[3][3]; maxtrix(){ r=c=0; memset(val,0,sizeof(val)); } void identity(int l){ r=c=l; for(int i=1;i<=l;i++) val[i][i]=1; } maxtrix operator * (maxtrix const b){ // c==b.r maxtrix now; now.r=r; now.c=b.c; for(int i=1;i<=r;i++) for(int j=1;j<=b.c;j++) for(int k=1;k<=c;k++) now.val[i][j]=(1ll*now.val[i][j]+1ll*val[i][k]*b.val[k][j])%mod; return now; } maxtrix operator ^ (ll b){ maxtrix base,now; base=*this; now.identity(this->r); while(b){ if(b&1) now=now*base; base=base*base; b>>=1; } return now; } }g,d; ll n; int main(){ while(cin>>n){ if(n<=2){printf("1\n");continue;} g.r=g.c=2; g.val[1][1]=0;g.val[1][2]=g.val[2][1]=g.val[2][2]=1; d.r=1;d.c=2; d.val[1][1]=d.val[1][2]=1; g=g^(n-2); d=d*g; printf("%d\n",d.val[1][2]); } return 0; }
- 最后的皮皮话
- 下午效率不高,得再集中精神点。(中午睡久了吧……)
- 从考试来看,有些常用的东西和知识点要复习啊,不然学了白学一样。
- 做题时要多考虑,否则到处都是漏洞。
- 刷题速度要加快呢,时间不多了。
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas