你是能看到第一題的 friends 呢。 ——hjaios
衆所周知,小蔥同窗擅長計算,尤爲擅長計算組合數,但這個題和組合數沒什麼關係。算法
網址壓縮是現實世界的一個重要問題,隨着網址數量的日益增加,長網址的存儲已經給現現在的網絡帶來了巨大的壓力。爲了解決這個問題,網址壓縮已經成爲了一件迫在眉睫的事情(以上都是我瞎編的)。網絡
更具體來講,網址壓縮的目標是但願將較長的網址變爲更短的網址,例如咱們能夠將 https://www.baidu.com 壓縮爲 http://sb.cn/。爲了更加形式化咱們的問題,測試
咱們如今的任務是給定N個只包含小寫字母的字符串,你須要輸出對這N個字符串進行壓縮的結果。你可使用任意的壓縮算法,但你須要保證知足以下的性質:spa
一、壓縮的結果字符串仍然只有小寫字母。code
二、壓縮的結果不能是空串,且長度必需要比原來的字符串短。orm
三、相同的字符串壓縮結果必須相同,不一樣的字符串壓縮結果必須不一樣。blog
任意知足上述條件的壓縮方法都是正確的,因此你的目標就是對給定的N個字符串進行壓縮。數據保證有解排序
第一行一個整數𝑁。ip
接下來𝑁行每行一個字符串。
輸出𝑁行每行一個字符串表明壓縮的結果。
4
jzm
bilibili
hhhhh
jzm
ha
bilibil
hhhh
ha
對於100%的數據,𝑁 ≤ 1000,字符串長度≤ 50。大部分測試點直接隨機造
數據,小部分測試點爲構造數據。
全損壓縮
先把全部的字符串讀入,而後按照長度從小到大排序,而後一個一個壓縮(a,b,c,...,z,aa,ab...這樣子)
好像還有一個奇技淫巧,只須要排序以後把第一個字符刪掉就能夠過這道題
然鵝並無卡掉這種作法
#include<cstdio> #include<cstdlib> #include<cstring> #include<map> #include<string> #include<iostream> #include<algorithm> using namespace std; const int maxn=1010; map<string,string> ma; string z[maxn]; int n,l=1,res[233],y[maxn]; bool cmp(int a,int b) { return z[a]<z[b]; } int main() { cin >> n; for (int a=1;a<=n;a++) { cin>>z[a]; y[a]=a; } res[1]=1; sort(y+1,y+n+1,cmp); for (int a=1;a<=n;a++) { string now = z[y[a]]; if (ma.count(now)!=0) ; else { string cur = ""; for (int a=l;a>=1;a--) cur = cur + (char)(res[a]+'a'-1); ma[now] = cur; res[1]++; for (int a=1;a<=l;a++) if (res[a]>26) { res[a]=1; res[a+1]++; } if (res[l+1]) l++; } } for (int a=1;a<=n;a++) cout << ma[z[a]] << endl; return 0; }
你是能看到第二題的 friends 呢。
——aoao
衆所周知,小蔥同窗擅長計算,尤爲擅長計算組合數,但這個題和組合數沒什麼關係。
Paradeus 是一個新興的宗教組織,該組織包含了𝑁 − 1個 Nyto,以及一個Mercurows 總共𝑁我的組成。每一個 Nyto 都是被其餘某我的傳教而進入的 Paradeus,而 Mercurows 是宗教的創立者,也就是說 Mercurows 並無被任何人拉進組織。這張記錄了每一個人是由誰拉進傳銷組織的記錄被視爲 Paradeus 的教義,一直被廣爲傳頌。
然而,隨着歲月的流逝,有不法分子開始對 Paradeus 的教義發動了攻擊。不法分子在 Paradeus 的教義上添加了一條記錄(𝑎, 𝑏),表明𝑏是由𝑎介紹入教的。這條記錄的加入致使 Nyto 們發現教義已經不合法了。爲了復興教義,教徒們決定找到這條被不法分子加入的記錄,並將其刪除以恢復教義的榮光。更具體的說,如今給定𝑁對記錄(𝑎𝑖, 𝑏𝑖)表明是𝑎𝑖將𝑏𝑖拉入教的。注意這𝑁條記錄包含了被不法分子添加的那一條。如今咱們但願你找到某一條記錄,使得刪掉這條記錄以後剩下的𝑁 − 1條記錄可以造成合法的教義。要注意的是,教義並沒有標註誰是 Mercurows,因此任何人都有多是 Mercurows。
一棵外向樹(全部邊從根向外指),加一條邊,找出這條邊讓他編號儘量大
第一行一個數𝑁表明人數。接下來𝑁行每行兩個數𝑎𝑖, 𝑏𝑖表明一條記錄。
一行一個數表明刪掉第幾條記錄可以使得教義合法。若是有多種方案,輸出編號最大的方案。數據保證有解。
3
1 2
1 3
2 3
3
對於40%的數據,𝑁 ≤ 1000。
對於另外20%的數據,可能成爲 Mercurows 的人必定只有一個。
對於100%的數據,1 ≤ 𝑁 ≤ 10^5。
討論
1.知道根節點是誰 看看有沒有入度爲0的點
橫叉邊和返祖邊
其實是一種狀況,就是有一個點入度爲2
暴力刪邊兩次看看連不連通(然而我直接貪心取了最大的,而後100-->80)
2.不能找到一個入度爲0的點 -->必定有環
在這個環上刪除任何一個邊均可以
怎麼找環?BFS,並查集,tarjan
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int maxn=100010; int n,en,head,tail,in[maxn],ex[maxn][2],q[maxn],f[maxn],pre[maxn][2]; bool use[maxn]; struct edge { int s,e,p; edge *next; }*v[maxn],ed[maxn]; void add_edge(int s,int e,int p) { en++; ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->p=p; in[e]++; ex[en][0]=s;ex[en][1]=e; } int get(int p) { if (f[p]==p) return p; else return get(f[p]); } void init() { en=0; memset(v,0,sizeof(v)); memset(in,0,sizeof(in)); } void read() { scanf("%d",&n); for (int a=1;a<=n;a++) { int s,e; scanf("%d%d",&s,&e); add_edge(s,e,a); } } bool work1(int p,int d) { memset(use,false,sizeof(use)); use[p]=true; head=tail=1; q[1]=p; for (;head<=tail;) { int p=q[head++]; for (edge *e=v[p];e;e=e->next) if (e->p!=d) { if (use[e->e]) return false; use[e->e]=true; pre[e->e][0]=p; pre[e->e][1]=e->p; q[++tail]=e->e; } } for (int a=1;a<=n;a++) if (!use[a]) return false; return true; } int work2(int p) { memset(use,false,sizeof(use)); use[p]=true; head=tail=1; q[1]=p; for (;head<=tail;) { int p=q[head++]; for (edge *e=v[p];e;e=e->next) { if (use[e->e]) return e->p; use[e->e]=true; q[++tail]=e->e; } } return -1; } int work() { for (int a=1;a<=n;a++) if (in[a]==2) { int p1=-1,p2=-1; for (int b=1;b<=n;b++) if (ex[b][1]==a) { if (p1==-1) p1=b; else p2=b; } if (p1>p2) swap(p1,p2); for (int b=1;b<=n;b++) if (in[b]==0) { if (work1(b,p2)) return p2; else return p1; } } for (int a=1;a<=n;a++) if (in[a]==0) return work2(a); for (int a=1;a<=n;a++) f[a]=a; for (int a=1;a<=n;a++) { int f1=get(ex[a][0]); int f2=get(ex[a][1]); if (f1==f2) { work1(ex[a][1],a); int p=ex[a][1],ans=a; while (p!=ex[a][1]) { ans=max(ans,pre[p][1]); p=pre[p][0]; } return ans; } f[f1]=f2; } return -1; } int main() { init(); read(); int p=work(); printf("%d\n",p); return 0; }
個人菜雞80分代碼(個人找環是在開始建了雙向邊,而後直接dfs,可是在上面的第一種狀況直接取了max致使80pts)
#include<cstdio> #include<iostream> #include<cstdlib> #include<iomanip> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; const int N=100005; int n; int head[N],ecnt,ver[N]; struct edge { int to,nxt; }edg[N<<1]; inline void add(int u,int v) { edg[++ecnt].to=v; edg[ecnt].nxt=head[u]; head[u]=ecnt; edg[ecnt+n].to=u; edg[ecnt+n].nxt=head[v]; head[v]=ecnt+n; } int in[N],out[N]; bool flag=0; void checkout() { for(int i=1;i<=n;i++) { if(out[i]>1) { int maxn=-1; for(int j=head[i];j;j=edg[j].nxt) { if(j<=n) maxn=max(maxn,j);//這裏不對,應該刪掉每一條邊以後判斷連通性 } printf("%d\n",maxn); flag=1; } } } bool huan[N]; bool vis[N]; int dfn[N]; int fa[N]; int cnt,sum; int ans[N]; void dfs(int now) { dfn[now]=++cnt; for(int i=head[now],v;i;i=edg[i].nxt) { v=edg[i].to; if(v==fa[now]) continue; if(dfn[v]) { //if(dfn[v]<dfn[now]) continue; ans[++sum]=v,huan[v]=1; for(;v!=now;v=fa[v]) ans[++sum]=fa[v],huan[fa[v]]=1; } else fa[v]=now,dfs(v); } } void checkhuan() { dfs(1); } int zhx=-1; void getans(int x) { for(int i=head[x];i;i=edg[i].nxt) { if(i<=n) { int v=edg[i].to; if(huan[v]==1&&vis[v]==0) { vis[v]=1; zhx=max(zhx,i); getans(v); } } } } int main() { // freopen("remove.in","r",stdin); // freopen("remove.out","w",stdout); scanf("%d",&n); for(int i=1,u,v;i<=n;i++) { scanf("%d%d",&u,&v); add(v,u); in[u]++; out[v]++; } checkout(); if(flag==1) return 0; checkhuan(); getans(ans[1]); for(int i=1;i<=sum;i++) printf("%d ",ans[i]); } /* 5 5 2 1 2 2 3 3 1 2 4 */
你是能看到第三題的 friends 呢。
——laekov
衆所周知,小蔥同窗擅長計算,尤爲擅長計算組合數,但這個題和組合數沒什麼關係。
自古以來,遞茶就是一種傳統美德,而給大佬遞茶更是普遍活躍於表情包的存在。如今爲了模擬給大佬遞茶的工做,Alice 和 Bob 開始了遞茶操做。一開始Alice 和 Bob 都有一個杯子裏面裝了𝑁噸的茶。如今每次 Alice 會等機率地隨機向垃圾桶裏面倒入4𝐾, 3𝐾, 2𝐾或者𝐾噸的茶,而且若是 Alice 倒了𝑥噸的茶,Bob 就會向垃圾桶裏面導入4𝐾−𝑥噸的茶。注意每次操做的時候 Alice 或者 Bob 的茶有可能不夠多,這個時候就能倒多少到多少。如今問 Alice 在四種操做徹底等機率的狀況下,Alice 先把本身的茶倒光的機率加上 Alice 和 Bob 同時把茶倒光的機率的一半是多少。注意,Alice 和 Bob 每輪倒茶都是同時開始同時結束的。
第一行兩個整數𝑁,𝐾。
輸出一行一個六位實數表明答案。
2 1
0.625000
對於30%的數據,1 ≤ 𝑁,𝐾 ≤ 100。
對於60%的數據,1 ≤ 𝑁,𝐾 ≤ 1000。
對於另外20%的數據,𝐾 = 1。
對於100%的數據,1 ≤ 𝑁,𝐾 ≤ 10^9。
首先,k其實沒有區別
N=10,k=5和n=2,k=1是同樣的
把讀進來的n變成n/k(上取整),k變成1
給你一個數,問另一個數(要注意這種問題能夠經過某種玄學的方式找規律)
打表???
1. 爆搜
能夠加上記憶化 f[i][j]表示a裏面有i,b裏面有j的機率是多少
最後求f[n][n]
F[0][j]=1,f[i][0]=0,f[0][0]=0.5
轉移 f[i][j]=0.25*(f[i-4][j]+f[i-3][j-1]+f[i-2][j-2]+f[i-1][j-3]) 70pts
複雜度n^2
打表:隨着n的增加,機率在增加
還有:答案只要求保留六位小數
因此,當n>?時 只須要輸出1.000000??????
什麼玄學東西????
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std; const int maxn=201; int n,k; double f[maxn][maxn]; bool g[maxn][maxn]; double dfs(int n,int m) { if (n<=0 && m<=0) return 0.5; if (n<=0) return 1.0; if (m<=0) return 0.0; if (g[n][m]) return f[n][m]; g[n][m]=true; for (int a=1;a<=4;a++) f[n][m]+=0.25*dfs(n-a,m-4+a); return f[n][m]; } double work(int n,int k) { if (n/k>=maxn) return 1.0; return dfs((n/k)+(n%k?1:0),(n/k)+(n%k?1:0)); } int main() { scanf("%d%d",&n,&k); printf("%.6lf\n",work(n,k)); return 0; }
給大佬遞茶
【問題描述】
你是能看到第三題的 friends 呢。
——laekov
衆所周知,小蔥同窗擅長計算,尤爲擅長計算組合數,但這個題和組合數沒
什麼關係。
自古以來,遞茶就是一種傳統美德,而給大佬遞茶更是普遍活躍於表情包的
存在。如今爲了模擬給大佬遞茶的工做,Alice 和 Bob 開始了遞茶操做。一開始
Alice 和 Bob 都有一個杯子裏面裝了𝑁噸的茶。如今每次 Alice 會等機率地隨機向
垃圾桶裏面倒入4𝐾, 3𝐾, 2𝐾或者𝐾噸的茶,而且若是 Alice 倒了𝑥噸的茶,Bob 就
會向垃圾桶裏面導入4𝐾− 𝑥噸的茶。注意每次操做的時候 Alice 或者 Bob 的茶有
可能不夠多,這個時候就能倒多少到多少。如今問 Alice 在四種操做徹底等機率
的狀況下,Alice 先把本身的茶倒光的機率加上 Alice 和 Bob 同時把茶倒光的概
率的一半是多少。注意,Alice 和 Bob 每輪倒茶都是同時開始同時結束的。