ps:D题挂了,最后只有三个。。。。
E题是赛后看着一群大神的代码YY的(网上找不到题解,好奇怪,肿么都没人写的)
之所以这么迟是因为一直在纠结E题
A:如果第一个人能放,那就放在中间的位置,然后第二个人不管放哪第一个人总有对称的放法
B:水题
C:简单贪心,错了一次
D:给你一幅图,假如在地板上铺上无限的同样的图,判断从S出发能否走到无限远的地方
只需要判断能否从一幅图的一个点走到相对位置相同的另一幅图中的那个点即可,通过取余来表示无限幅地图
E:给你一棵树,然后又给你坐标图上的n个点,让你按照树的构成将坐标连接起来,即给所有的坐标点一个编号,将树种的点与坐标对应起来
树中相交的边 在坐标中体现 的线段也相交与一个点 ,不相邻的在坐标系中也不相邻
即 将坐标适当连线,重现树的形状
做法:
dfs预处理某个点有几个子孙节点
找一个最左下的点,这个点为根,对其它坐标极角排序,相当于把坐标划分了界限了
排好序后一段连续的坐标内部自己连线的话就不会和其它不应该交到的边相交了,比如当前要构造以u为根的子树
那么应该选出连续的son[u]个点,继续递归构造,这些点和下一段连续的点内部各自的线段肯定不会相交
贴个E的代码

/* ps:我的代码为什么总是慢点 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef __int64 lld; const int maxn = 1600; int pnt[maxn*2],h[maxn],nxt[maxn*2],son[maxn],E,n; int ans[maxn]; struct Point{ lld x,y; int id; bool operator<(const Point &cmp) const{ return x<cmp.x||(x==cmp.x&&y<cmp.y); } }p[maxn]; inline lld det(Point a,Point b,Point c){ return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); } Point cent; inline void add(int h[],int a,int b){ pnt[++E] = b; nxt[E] = h[a]; h[a] = E; } void dfs(int u,int fa){ son[u]=1; for(int i=h[u];i;i=nxt[i]){ int v=pnt[i]; if(v==fa) continue; dfs(v,u); son[u]+=son[v]; } } int cmpAng(Point a,Point b){//sort around "cent" return det(cent,a,b)>0; } void solve(int rt,int fa,int lb,int rb){ int pos=lb; for(int i=lb+1;i<=rb;i++){ if(p[i]<p[pos]){ cent=p[i]; pos=i; } } if(lb!=pos) swap(p[lb],p[pos]); cent = p[lb]; ans[p[lb].id]=rt; sort(p+lb+1,p+rb+1,cmpAng); int left=lb+1; for(int i=h[rt];i;i=nxt[i]){ int v=pnt[i]; if(v==fa) continue; solve(v,rt,left,left+son[v]-1); left+=son[v]; } } int main(){ int a,b,i; scanf("%d",&n); for(i=0;i<n-1;i++){ scanf("%d%d",&a,&b);a--;b--; add(h,a,b); add(h,b,a); } dfs(0,-1); for(i=0;i<n;i++){ scanf("%I64d%I64d",&p[i].x,&p[i].y); p[i].id=i; } solve(0,-1,0,n-1); for(i=0;i<n;i++) printf("%d ",ans[i]+1); puts(""); return 0; }
CF 196D the next good string
给你一个整数m 和一个字符串s
输出一个字符串,使得这个字符串的字典序大于s(且是最小的字典序)且满足不存在长度大于等于m的回文子串
利用回文串的性质,只要修改当前某个字符后,前m个字符 和 前m+1个字符不为回文串,那么就可以继续构造,构造完后绝对不会产生大于m的回文子串
可以反证,如果构造完后(即字符串已经不存在长度为m或m+1的回文子串)存在大于等于m的回文子串,那么肯定会出现 在某个位置往前m或m+1(考虑奇偶)的子串是回文串 的情况,所以矛盾
另外,判断回文用的是哈希,比较简便。

#include<cstdio> #include<cstring> const int P = 100000007; const int N = 400010; int p[N],l[N],r[N],m; char ans[N],s[N]; int n; bool ok(int i,int x){ if(++i<x) return 0; return ((r[i]-r[i-x]*p[x])*p[i-x])==(l[i]-l[i-x]); } int dfs(int i,int has){ if(i==n) return puts(ans),1; for(ans[i]=(has?s[i]:'a');ans[i]<='z';ans[i]++){ l[i+1]=l[i]+ans[i]*p[i]; r[i+1]=r[i]*P+ans[i]; if(!ok(i,m) && !ok(i,m+1) && dfs(i+1,has&&(s[i]==ans[i]))) return 1; } return 0; } int main() { scanf("%d%s",&m,s); int i=(n=strlen(s))-1; for(;i>=0&&s[i]=='z';i--) s[i]='a'; if(i<0) return puts("Impossible"),0; s[i]++; p[0]=1; for(i=1;i<N;i++) p[i]=p[i-1]*P; if(!dfs(0,1)) puts("Impossible"); return 0; }
下面是div1的E题(看结题报告看不懂,囧,看代码反而就懂了,我就是个代码控啊。。。)
最短路径的调试还真是慢轻松的,不像DP。
给你一幅图,再给你其中的k个点,要求从1出发,经过所有的k个点的最小路程
注意:这k个点中如果某两个点都经过了,那么就可以从一个点瞬间移动到令一个点
个人觉得题目的描述很符合实际,而且有点隐蔽。
其实可以瞬间移动就代表相邻两个港口之间的路径只需要经过一次就好了,花费就是他们之间的路径的权值,即生成树!!
所以,要构造另外一幅图,图中的点只剩港口。再求最小生成树即可
关键是如何建边:
港口之间的新边是从一个港口到另一个港口的最短路径,如果暴力的话应该会超时
直接从所有的港口出发,走一遍dijkstra,求出这些点到其他点的最短路径,并记录最短路径对应的起点是谁。
然后对于原图边a->b,如果a,b的最短路径来自于不同的点,就可以给这两个起点(港口)连一条边dis[a]+dis[b]+w[a->b];

#include<cstdio> #include<cstring> #include<queue> #include<vector> #include<algorithm> #include<iostream> using namespace std; typedef __int64 lld; const lld inf = 1000000000000000000LL; const int maxn = 100010; struct Edge{ int t,w; Edge(){} Edge(int t,int w){ this->t=t; this->w=w; } }; int from[maxn]; lld disp[maxn],dis0[maxn]; struct PP{ int a,b; lld c; PP(){} PP(int a,int b,lld c){ this->a=a; this->b=b; this->c=c; } bool operator < (const PP &cmp) const{ return c<cmp.c; } }; vector<Edge> edge[maxn]; void add(int a,int b,int c){ edge[a].push_back(Edge(b,c)); } bool used[maxn]; int n; void dijkstra(vector<int> src,lld dis[]) { priority_queue<pair<lld,int> > Q; memset(used,false,sizeof(used)); fill(dis+1,dis+n+1,inf); for(vector<int>::iterator it=src.begin();it!=src.end();it++) { from[*it]=*it; dis[*it]=0; Q.push(make_pair(-dis[*it],*it)); } while(!Q.empty()){ int fr=Q.top().second; Q.pop(); if(used[fr]) continue; used[fr]=true; for(vector<Edge>::iterator it=edge[fr].begin();it!=edge[fr].end();it++) { lld di=dis[fr]+it->w; if(di<dis[it->t]) { dis[it->t]=di; from[it->t]=from[fr]; Q.push(make_pair(-dis[it->t],it->t)); } } } } int fa[maxn]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} int main() { int m,k,i,j,a,b,c; while(scanf("%d%d",&n,&m)!=EOF){ for(i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } vector<int> portal; scanf("%d",&k); for(i=0;i<k;i++){ scanf("%d",&j); portal.push_back(j); } vector<int> s;s.push_back(1); dijkstra(s,dis0); dijkstra(portal,disp); lld ans=inf; for(vector<int>::iterator d=portal.begin();d!=portal.end();d++){ if(dis0[*d]<ans) ans=dis0[*d]; } for(i=1;i<=n;i++) fa[i]=i; vector<PP> sol; for(i=1;i<=n;i++){ vector<Edge> ::iterator it; for(it=edge[i].begin();it!=edge[i].end();it++){ if(from[it->t]!=from[i]){ sol.push_back(PP(from[i],from[it->t],(lld)it->w+disp[i]+disp[it->t])); } } } sort(sol.begin(),sol.end()); for(vector<PP>::iterator it=sol.begin();it!=sol.end();it++){ a=it->a;b=it->b;// printf("%d %d %d\n",a,b,it->c); int x=find(a),y=find(b); if(x!=y){ ans+=it->c; fa[x]=y; } } printf("%I64d\n",ans); } return 0; } /* 6 8 1 3 2 1 4 1 1 5 3 1 6 4 5 3 2 6 4 7 2 5 1 2 6 9 4 4 2 3 1 */