@(CSP模擬賽20190922)
兩天的一二題都挺水的,指望原本能夠得400,可是沒有一天是得完了能得的分的。ui
優美的字符串(string)
【題目描述】
小 Y 送給小 F 一個字符串做爲禮物,這個字符串只由’a’ 和’b’ 組成。
因爲小 F 患有嚴重的強迫症,他以爲這個字符串並不優美,他決定對它作一些
操做:
每次操做從字符串中選擇一個’ab’ 子串,並將其替換爲’bba’。
若是一個字符串的全部’b’ 都在全部’a’ 前面,他認爲這個字符串是優美的。
如今小 F 想知道,最少須要多少次操做,能使這個字符串是優美的,或者這個字
符串不可能變成優美的。
【輸入格式】
從文件 string.in 中讀入數據。
一行一個只由’a’ 和’b’ 組成的字符串。
【輸出格式】
輸出到文件 string.out 中。
輸出一行一個整數,若是無解,輸出「-1」。不然輸出最少操做次數對.
1000000007
取. 模. 。spa
大水題,手推五分鐘就切了。code
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=1000007; const ll mod=1000000007; ll dis[N]; char c[N]; template<class T>inline void read(T &res){ static char ch;T flag=1; while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1; res=ch-48; while((ch=getchar())>='0'&&ch<='9') res=(res<<1)+(res<<3)+ch-48; res*=flag; } int main() { freopen("string.in","r",stdin); freopen("string.out","w",stdout); scanf("%s",c); int n=strlen(c),tot=0; ll ans=0; c[n]='a'; for(int i=n-1,last=n;i>=0;--i) if(c[i]=='a'){ dis[++tot]=last-i-1; last=i; } for(int i=1;i<=tot;++i){ ans=(ans+dis[i])%mod; dis[i+1]=(dis[i]*2+dis[i+1])%mod; } printf("%lld\n",ans); return 0; }
【題目描述】
小 X 同窗有很強的計算能力,如今他正在玩一個遊戲。
如今有一個正整數 x,每次操做他會將當前的數變爲這個數寫成二進制後 1 的
個數。
小 X 不斷的進行操做,直到這個數變成 1 爲止。
因爲小 X 的計算能力很強,他如今給出一個 n,他想知道有多少不超過 n 的正整
數會在 k 次操做後變成 1。因爲答案可能很大,請對 1000000007 取模。
【輸入格式】
從文件 number.in 中讀入數據。
第一行一個用二進制表示的正整數 n,含義如題目描述。
第二行一個整數 k, 含義如題目描述。
【輸出格式】
輸出到文件 number.out 中。
輸出一個整數,表示答案對 1000000007 取模的值。遊戲
發現2^1000通過一次計算就降到了1000一下,因此能夠1000一下暴力搜索,而後再用組合數求值。
記得特判下k=0和1的狀況ci
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=10007; const ll mod=1000000007; int n,k,lim,num[N]; ll ans,fac[N]={1}; char ch[N]; ll fp(ll x,ll k){ ll ans=1,s=x; while(k){ if(k&1) ans=ans*s%mod; k>>=1; s=s*s%mod; } return ans; } inline ll inv(ll x){return fp(x,mod-2);} inline ll C(ll n,ll m){ if(n>m||n<0||m<0) return 0; return fac[m]*inv(fac[n])%mod*inv(fac[m-n])%mod; } ll cal(int x){ ll res=0,cnt=0; for(int i=0;i<n;++i) if(num[i]==1){ res=(res+C(x-cnt,n-i-1))%mod; ++cnt; } if(cnt==x) res=(res+1)%mod; return res; } void dfs(int onenum,int stp){ if(stp==k){ ans=(ans+cal(onenum))%mod; return; } if(onenum>lim) return; for(int i=max(fp(2,onenum)-1,2ll);i<=n;++i){ int cnt=0,temp=i; while(temp){ if(temp&1) ++cnt; temp>>=1; } if(cnt==onenum) dfs(i,stp+1); } } int main() { freopen("number.in","r",stdin); freopen("number.out","w",stdout); scanf("%s",ch); n=strlen(ch); scanf("%d",&k); if(k==0){ printf("1\n"); return 0; } for(int i=0;i<n;++i) num[i]=ch[i]-'0'; lim=log(n)/log(2)+1; for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod; dfs(1,1); if(k==1) --ans; printf("%lld\n",ans); return 0; }
【題目描述】
S 市的有着很是特殊的城市規劃,能夠把它抽象成有 n 個點 n 條邊的連通圖。
S 市的市長對這樣的城市規劃十分不滿意,他想刪去其中的一條路使得任意兩點間
有且僅有一條簡單路徑。
S 市的市民對這樣的城市規劃也十分不滿意,具體地,市民的不滿意度爲任意兩點
間最短距離的最大值。
如今小 X 想知道,刪去知足條件的一條道路後,市民不滿意度的最小值。
【輸入格式】
從文件 city.in 中讀入數據。
第一行一個正整數 n,表示城市的點數和邊數。
接下來 n 行,每行三個正整數 ui
, vi
,wi,表示每條邊的兩個端點和長度。
【輸出格式】
輸出到文件 city.out 中。
輸出一個整數,表示答案字符串
考慮刪掉一條邊後,什麼樣的一條鏈會成爲直徑:
把這個圖當作是不少棵樹由一個環相連:
1.一棵樹的直徑就是這個圖的直徑。
2.兩個樹最深的兩個點之間的路徑。
刪掉環上一條邊顯然不會影響第一種狀況,考慮最小化第二種狀況:
假設環的長度爲k,環上的點爲a1,a2,...,ak,令a0=ak。
令si表示ai到a1的距離。顯然這是一個前綴和。
以這個點爲根的樹上最深的點深度爲dep1,dep2,…,depk。
若是斷開的路徑爲e(a{i-1},ai),分爲三種狀況:
1.從1-i-1選兩個點能取到最大值。
2.從i-k選兩個點取到最大值。
3.先後各選一個點取到最大值。
對於每條邊,咱們須要快速的求出三種狀況的max。
對於第一種狀況,兩點x,y間的距離爲depx+depy+(sy-sx)=(depx-sx)+(depy+sy)
對於第二種狀況結果同第一種狀況。
對於第三種狀況:設x<y,距離爲depx+depy+(sk-(sy-sx))=sk+(depx+sx)+(depy-sy)。
咱們須要讓三種狀況的最大值最小。考慮求每種狀況的最大值:
預處理depi-si,depi+si,維護前綴和後綴最大值,就能獲得每種狀況的最大值,記錄全部最大值的最小值,就是答案。get
反正我不會string
【題目描述】
爲緩解 S 城與日俱增的交通壓力,S 城的市長準備修一條路。
S 城共有 n 個街區,它們由 m 條雙向道路相連,每條道路的長度相等。
做爲 S 城的天才,小 X 瞭解到 S 城的交通壓力主要來自於最繁華的 S 街區和 T
街區。若是新修的路不能使 S 街區到 T 街區的距離縮短,就不能緩解 S 城的交通壓力。
S 城的市長天然不瞭解這一點。如今小 X 想知道,有多少種修路方案不能緩解 S
城的交通壓力。
注意,對於修路方案 (ui
, ti) 和 (ti
, ui) 視爲同一種方案,新修的路不能在原圖中存在。
【輸入格式】
從文件 road.in 中讀入數據。
第一行四個整數 n, m, S, T。表示 S 城的街區數,道路數,繁華的兩個街區的編號。
接下來 m 行,每行兩個數 ui
, vi 表示一條道路上的兩個街區。
圖中無重邊和自環。
【輸出格式】
輸出到文件 road.out 中。
輸出一行一個整數。表示不能緩解交通壓力的方案數。it
bfs求任意兩點間的最短路,而後暴力枚舉任意兩點連邊是否可使最短路變短(相似dijsktra和floyed的鬆弛操做)
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=2007; int n,m,S,T,tot,ans,head[N],dis[N][N]; bool vis[N],edge[N][N]; struct Edge{ int to,next; }e[N<<1]; void add(int from,int to){ e[++tot].to=to; e[tot].next=head[from]; head[from]=tot; } template<class T>inline void read(T &res){ static char ch;T flag=1; while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1; res=ch-48; while((ch=getchar())>='0'&&ch<='9') res=(res<<1)+(res<<3)+ch-48; res*=flag; } queue<int> q; void bfs(int sta){ memset(vis,false,sizeof(vis)); q.push(sta); vis[sta]=true; while(q.size()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(vis[v]) continue; vis[v]=true; dis[sta][v]=dis[sta][u]+1; q.push(v); } } } int main() { freopen("road.in","r",stdin); freopen("road.out","w",stdout); read(n);read(m);read(S);read(T); for(int i=1;i<=m;++i){ int u,v; read(u);read(v); add(u,v);add(v,u); edge[u][v]=edge[v][u]=true; } for(int i=1;i<=n;++i) bfs(i); for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j){ if(edge[i][j]) continue; if(dis[S][T]>dis[S][i]+dis[j][T]+1||dis[S][T]>dis[S][j]+dis[i][T]+1){ ++ans; // printf("%d %d\n",i,j); } } printf("%d\n",n*(n-1)/2-m-ans); return 0; }
【題目描述】
everlasting 有 n 個神奇的集合,編號爲 1n。開始時它們都是空的,如今 everlasting
要對它們進行兩種操做:
顯然能夠開n個線段樹來維護n個元素的覆蓋狀況,動態開點防止空間爆炸。剩下就很簡單了。
考場調了2.5h也沒打出來,旁邊的myg大佬一下就打完了,再此膜拜。
#include<cstdio> using namespace std; #define ll long long const ll mod=998244353; const int N=8000007; int n,q,ndnum,root,a[N>>5],ls[N],rs[N]; ll sum[N],fla[N],flm[N]; template<class T>inline void read(T &res){ static char ch;T flag=1; while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1; res=ch-48; while((ch=getchar())>='0'&&ch<='9') res=(res<<1)+(res<<3)+ch-48; res*=flag; } int build(int l,int r){ int p=++ndnum; if(l==r){ sum[p]=0; flm[p]=1; return p; } int mid=(l+r)>>1; ls[p]=build(l,mid); rs[p]=build(mid+1,r); sum[p]=sum[ls[p]]+sum[rs[p]]; flm[p]=1; return p; } void pushdown(int p,int l,int r){ int mid=(l+r)>>1; sum[ls[p]]=(sum[ls[p]]*flm[p]%mod+(mid-l+1)*fla[p]%mod)%mod; sum[rs[p]]=(sum[rs[p]]*flm[p]%mod+(r-mid)*fla[p]%mod)%mod; fla[ls[p]]=(fla[ls[p]]*flm[p]%mod+fla[p])%mod; fla[rs[p]]=(fla[rs[p]]*flm[p]%mod+fla[p])%mod; flm[ls[p]]=flm[ls[p]]*flm[p]%mod; flm[rs[p]]=flm[rs[p]]*flm[p]%mod; fla[p]=0;flm[p]=1; } int xl,xr,yl,yr,x; ll query(int l,int r,int p){ if(xl<=l&&r<=xr) return sum[p]; pushdown(p,l,r); int mid=(l+r)>>1; ll res=0; if(xl<=mid) res+=query(l,mid,ls[p]); if(xr>mid) res+=query(mid+1,r,rs[p]); return res%mod; } int sett(int l,int r,int p){ if(p==0) p=++ndnum; if(yl<=l&&r<=yr){ sum[p]=1; fla[p]=true; return p; } int mid=(l+r)>>1; if(yl<=mid){ if(!ls[p]) ls[p]=++ndnum; ls[p]=sett(l,mid,ls[p]); } if(yr>mid){ if(!rs[p]) rs[p]=++ndnum; rs[p]=sett(mid+1,r,rs[p]); } if(sum[ls[p]]==sum[rs[p]]) sum[p]=sum[ls[p]]; else sum[p]=-1; return p; } int _get(int l,int r,int p){ if(yl<=l&&r<=yr) return sum[p]; int mid=(l+r)>>1; int la=100,ra=100; if(yl<=mid){ if(!ls[p]) ls[p]=++ndnum; if(fla[p]==1) sum[ls[p]]=fla[ls[p]]=1; la=_get(l,mid,ls[p]); } if(yr>mid){ if(!rs[p]) rs[p]=++ndnum; if(fla[p]==1) sum[rs[p]]=fla[rs[p]]=1; ra=_get(mid+1,r,rs[p]); } if(la==100) return ra; if(ra==100) return la; if(la==ra) return la; return -1; } void modify(int l,int r,int p,int c){ if(xl<=l&&r<=xr){ if(c==1){ sum[p]=(sum[p]+r-l+1)%mod; fla[p]=(fla[p]+1)%mod; return; } if(c==2){ sum[p]=sum[p]*2%mod; fla[p]=fla[p]*2%mod; flm[p]=flm[p]*2%mod; return; } yl=l,yr=r; int y=_get(1,n,x); if(y==0) c=1; else if(y==1) c=2; else c=0; if(c==1){ sum[p]=(sum[p]+r-l+1)%mod; fla[p]=(fla[p]+1)%mod; return; } if(c==2){ sum[p]=sum[p]*2%mod; fla[p]=fla[p]*2%mod; flm[p]=flm[p]*2%mod; return; } } pushdown(p,l,r); int mid=(l+r)>>1; if(xl<=mid) modify(l,mid,ls[p],c); if(xr>mid) modify(mid+1,r,rs[p],c); sum[p]=(sum[ls[p]]+sum[rs[p]])%mod; } int main() { freopen("multiset.in","r",stdin); freopen("multiset.out","w",stdout); read(n);read(q); ndnum=n; root=build(1,n); while(q--){ int opt; read(opt); if(opt==1){ read(xl);read(xr);read(x); modify(1,n,root,0); yl=xl;yr=xr; sett(1,n,x); } else if(opt==2){ read(xl);read(xr); printf("%lld\n",query(1,n,root)); } } // while(q--){ // int opt; // read(opt); // if(opt==1){ // read(yl);read(yr);read(x); // sett(1,n,x); // } // else if(opt==2){ // read(yl);read(yr);read(x); // printf("%d\n",_get(1,n,x)); // } // } return 0; }
【題目描述】
小 X 同窗以爲樹上問題太毒瘤了,因而決定將樹上的邊刪去,最終變成一個點。
如今有一個 n 個節點的樹,他的遊戲是這樣的: