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 */