小 C 正在玩一款排兵佈陣的遊戲。在遊戲中有 $n$ 座城堡,每局對戰由兩名玩家來爭奪這些城堡。每名玩家有 $m$ 名士兵,能夠向第 $i$ 座城堡派遣 $a_i$ 名士兵去爭奪這個城堡,使得總士兵數不超過 $m$。node
若是一名玩家向第 $i$ 座城堡派遣的士兵數嚴格大於對手派遣士兵數的兩倍,那麼這名玩家就佔領了這座城堡,得到 $i$ 分。c++
如今小 C 即將和其餘 $s$ 名玩家兩兩對戰,這 $s$ 場對決的派遣士兵方案必須相同。小 C 經過某些途徑得知了其餘 $s$ 名玩家即將使用的策略,他想知道他應該使用什麼策略來最大化本身的總分。git
因爲答案可能不惟一,你只須要輸出小 C 總分的最大值。ide
揹包問題ui
$f_{i,j}$ 表示選到前 $i$ 座城堡已經用了 $j$ 個士兵所能得到總分的最大值。spa
假若直接枚舉每座城堡派幾個士兵效率是 $O(nm^{2})$ ,可是咱們發現只有多獲勝一我的才能使總分增多,因此咱們能夠考慮枚舉每座城堡贏幾我的,效率變成 $O(nms)$ 。3d
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=105,M=2e4+5; int n,s,m,a[N][N],f[M]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } int main() { s=read();n=read();m=read(); for(int i=1;i<=s;i++)for(int j=1;j<=n;j++)a[j][i]=read()*2+1; for(int i=1;i<=n;i++)sort(a[i]+1,a[i]+1+s); for(int i=1;i<=n;i++)for(int j=m-1;j>=0;j--){ for(int k=1;k<=s;k++){ if(a[i][k]+j>m)break; f[a[i][k]+j]=max(f[a[i][k]+j],f[j]+k*i); } } int ans=0; for(int i=1;i<=m;i++)ans=max(ans,f[i]); printf("%d\n",ans); return 0; }
當一束光打到一層玻璃上時,有必定比例的光會穿過這層玻璃,必定比例的光會被反射回去,剩下的光被玻璃吸取。code
設對於任意 $x$,有 $x\times a_i\%$ 單位的光會穿過它,有 $x\times b_i\%$ 的會被反射回去。blog
如今 $n$ 層玻璃疊在一塊兒,有 $1$ 單位的光打到第 $1$ 層玻璃上,那麼有多少單位的光能穿過全部 $n$ 層玻璃呢?遊戲
$dp$ 問題
令 $f_{i}$ 表示 $1$ 單位光射入第 $i$ 層玻璃,能有多少穿過 $n$ 層玻璃。
令 $g_{i}$ 表示 $1$ 單位的光射入第 $i$ 層玻璃,最終能有多少光反射出去。
$$
f_{i}=a_i*(f_{i+1}+g_{i+1}*b_{i}*f_{i+1}+...)
$$
$$
f_{i}=a_i*f_{i+1}*\frac{1}{1-b_i*g_{i+1}}
$$
$$
gi=b_i+a_i*g_{i+1}*a_{i}+a_i*g_{i+1}*b_{i}*g_{i+1}*a_{i}...
$$
$$
g_{i}=b_i+a_i^2*g_{i+1}*\frac{1}{1-b_i*g_{i+1}}
$$
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=5e5+5,p=1e9+7,ny=570000004; int n,a[N],b[N],f[N],g[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } int main() { n=read(); for(int i=1;i<=n;i++){ a[i]=1ll*read()*ny%p;b[i]=1ll*read()*ny%p; } f[n]=a[n];g[n]=b[n]; for(int i=n-1;i;i--){ f[i]=1ll*a[i]*f[i+1]%p*ksm(mu(1,p-1ll*g[i+1]*b[i]%p),p-2)%p; g[i]=mu(b[i],1ll*a[i]*a[i]%p*g[i+1]%p*ksm(mu(1,p-1ll*b[i]*g[i+1]%p),p-2)%p); } printf("%d\n",f[1]); return 0; }
對於任意一個數列,若是能在有限次進行下列刪數操做後將其刪爲空數列,則稱這個數列能夠刪空。一次刪數操做定義以下:
- 記當前數列長度爲 $k$,則刪掉數列中全部等於 $k$ 的數。
現有一個長度爲 $n$ 的數列 $a$,有 $m$ 次修改操做,第 $i$ 次修改後你要回答:通過 $i$ 次修改後的數列 $a$,至少還須要修改幾個數纔可刪空?
每次修改操做爲單點修改或數列總體加一或數列總體減一。
對於一個數 $x$ 共有 $b[x]$ 個,那麼他所能覆蓋的區間爲 $[x-b[x]+1,x]$ ,答案即爲區間內沒有被覆蓋的數。
對於總體加減至關於把被覆蓋區間範圍總體移動。
能夠用線段樹維護。
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=6e5+5; int n,m,a[N],ans,mx,b[N],fir,mn[N<<2],num[N<<2],tag[N<<2]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void update(int x){ mn[x]=min(mn[x<<1],mn[x<<1|1]); num[x]=(mn[x]==mn[x<<1]?num[x<<1]:0)+(mn[x]==mn[x<<1|1]?num[x<<1|1]:0); } il void pushdown(int x){ if(!tag[x])return; int v=tag[x];tag[x]=0; mn[x<<1]+=v;mn[x<<1|1]+=v;tag[x<<1]+=v;tag[x<<1|1]+=v; } il void build(int x,int l,int r){ num[x]=r-l+1; if(l==r)return; int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); } il void change(int x,int l,int r,int ql,int qr,int v){ if(ql<=l&&r<=qr){ tag[x]+=v;mn[x]+=v; return; } int mid=(l+r)>>1;pushdown(x); if(ql<=mid)change(x<<1,l,mid,ql,qr,v); if(mid<qr)change(x<<1|1,mid+1,r,ql,qr,v); update(x); } il int query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ if(mn[x]==0)return num[x]; else return 0; } int res=0,mid=(l+r)>>1;pushdown(x); if(ql<=mid)res=query(x<<1,l,mid,ql,qr); if(mid<qr)res+=query(x<<1|1,mid+1,r,ql,qr); return res; } int main() { n=read();m=read(); mx=2*(n+m);fir=n+m;build(1,1,mx); for(int i=1;i<=n;i++)a[i]=read()+fir,b[a[i]]++; for(int i=fir+1;i<=fir+n;i++)if(b[i])change(1,1,mx,i-b[i]+1,i,1); for(int i=1;i<=m;i++){ int p=read(),x=read(); if(!p){ if(x==1){ if(b[fir+n])change(1,1,mx,fir+n-b[fir+n]+1,fir+n,-1); fir--; if(b[fir+1])change(1,1,mx,fir+1-b[fir+1]+1,fir+1,1); } else{ if(b[fir+1])change(1,1,mx,fir+1-b[fir+1]+1,fir+1,-1); fir++; if(b[fir+n])change(1,1,mx,fir+n-b[fir+n]+1,fir+n,1); } } else{ int now=a[p]; if(now<=fir+n&&now>fir)change(1,1,mx,now-b[now]+1,now-b[now]+1,-1);b[now]--; now=fir+x;b[now]++;a[p]=now; if(now<=fir+n&&now>fir)change(1,1,mx,now-b[now]+1,now-b[now]+1,1); } printf("%d\n",query(1,1,mx,fir+1,fir+n)); } return 0; }
Bezorath 大陸抵抗地災軍團入侵的戰爭進入了僵持的階段,世世代代生活在 Bezorath 這片大陸的精靈們開始尋找遠古時代諸神遺留的神器,試圖藉助神器的神祕力量幫助她們打敗地災軍團。
在付出了慘痛的代價後,精靈們從步步兇險的遠古戰場取回了一件保存尚無缺的神杖。但在經歷過那場全部史書都視爲禁忌的「諸神黃昏之戰」後,神杖上鑲嵌的奧術寶石已經殘缺,神力也幾乎消耗殆盡。精靈高層在至高會議中決定以舉國之力收集殘存至今的奧術寶石,並重金懸賞天下能工巧匠修復這件神杖。
你做爲神術一脈第五百零一位傳人,接受了這個艱鉅而神聖的使命。 神杖上從左到右鑲嵌了 $n$ 顆奧術寶石,奧術寶石一共有 $10$ 種,用數字 `0123456789` 表示。有些位置的寶石已經殘缺,用 `.` 表示,你須要用無缺的奧術寶石填補每一處殘缺的部分(每種奧術寶石個數不限,且不可以更換未殘缺的寶石)。古老的魔法書上記載了 $m$ 種咒語 $(S_i,V_i)$,其中 $S_i$ 是一個非空數字串,$V_i$ 是這種組合可以激發的神力。
神杖的初始神力值 $\mathrm{Magic} = 1$,每當神杖中出現了連續一段寶石與 $S_i$ 相等時,神力值 $\mathrm{Magic}$ 就會乘以 $V_i$。但神杖若是包含了太多咒語就再也不純淨致使神力下降:設 $c$ 爲神杖包含的咒語個數(若咒語類別相同但出現位置不一樣視爲屢次),神杖最終的神力值爲 $\sqrt[c]{\mathrm{Magic}}$。(若 $c = 0$ 則神杖最終神力值爲 $1$。)
例若有兩種咒語 $(01,3)$ 、$(10,4)$,那麼神杖 `0101` 的神力值爲 $\sqrt[3]{ 3 \times 4 \times 3}$。
你須要使修復好的神杖的最終的神力值最大,輸出任何一個解便可。
第一部的轉換仍是挺妙妙的
$$
val=\sqrt[c]{\prod_{i=1}^{c} V_{t_i}}
$$
若是對權值取對數
$$
ln^{val}=\frac{\sum_{i=1}^{c}V_{ti}}{c}
$$
這就是典型的分數規劃了
至少在 $ac$ 自動機上跑 $dp$ 。效率是 $O(sn)$ 。
#include<bits/stdc++.h> #define il inline #define db double #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1505; const db eps=1e-7; int n,m,ch[N][11],cnt=1,num[N],fa[N]; db val[N],eg[N],f[N][N]; char s[N],t[N],res; struct node{ int x,y,tp; }fr[N][N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void insert(db v){ int x=1,l=strlen(t+1); for(int i=1;i<=l;i++){ if(!ch[x][t[i]-'0'])ch[x][t[i]-'0']=++cnt; x=ch[x][t[i]-'0']; } num[x]++;val[x]+=v; } il void getfail(){ queue<int> q;fa[1]=1; for(int i=0;i<10;i++){ if(!ch[1][i])ch[1][i]=1; else q.push(ch[1][i]),fa[ch[1][i]]=1; } while(!q.empty()){ int x=q.front();q.pop(); val[x]+=val[fa[x]];num[x]+=num[fa[x]]; for(int i=0;i<10;i++){ if(!ch[x][i])ch[x][i]=ch[fa[x]][i]; else{ fa[ch[x][i]]=ch[fa[x]][i]; q.push(ch[x][i]); } } } } il bool pd(db m){ for(int i=1;i<=cnt;i++)eg[i]=m*num[i]-val[i]; for(int i=0;i<=n;i++)for(int j=1;j<=cnt;j++)f[i][j]=1e9; f[0][1]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=cnt;j++){ if(f[i-1][j]>1e6)continue; if(s[i]=='.'){ for(int k=0;k<10;k++){ if(f[i-1][j]+eg[ch[j][k]]<f[i][ch[j][k]]){ f[i][ch[j][k]]=f[i-1][j]+eg[ch[j][k]]; fr[i][ch[j][k]]=(node){i-1,j,k}; } } } else{ int k=s[i]-'0'; if(f[i-1][j]+eg[ch[j][k]]<f[i][ch[j][k]]){ f[i][ch[j][k]]=f[i-1][j]+eg[ch[j][k]]; fr[i][ch[j][k]]=(node){i-1,j,k}; } } } } for(int i=1;i<=cnt;i++)if(f[n][i]<0)return 1; return 0; } il void back(int x,int y){ if(!x)return; back(x-1,fr[x][y].y); printf("%c",fr[x][y].tp+'0'); } int main() { n=read();m=read(); scanf(" %s",s+1); for(int i=1;i<=m;i++){ scanf(" %s",t+1); db x=read();x=log2(x); insert(x); } getfail(); db l=0,r=100; while(r-l>eps){ db mid=(l+r)/2.0; if(pd(mid))l=mid; else r=mid; } pd(l);//cout<<l<<endl; for(int i=1;i<=cnt;i++)if(f[n][i]<0){ back(n,i);break; } puts(""); return 0; }