題庫中也有不少我想不出來的模擬賽的題目。作仍是必要的。作本身的題目 時間很緊 想一想本身的文化課 我又沒有那麼強 我必須得刷.ios
LINK:水題一道c++
發現是一道計數題 計數題拿高分的纔是王者,可是 計數題不取模就是在耍流氓了...很久沒寫高精了 順便寫寫。數組
此題 咱們發現 無論怎麼搞每一個教室都須要兩我的咱們不妨 先讓m-=2*n; 而後就是剩下的m我的的分配問題了 感受是組合數其實並不盡然。由於顯然不對...ide
這樣 對於一我的來講他有n種可能 那麼m我的呢?m^n 可是顯然有重複如第一我的選第二個 第二我的選第一個 和第一我的選第一個第二我的選第二個這樣是等效的...優化
考慮排列數對咱們答案的影響,無論排列的話其實除以一個m!便可。而後成功想錯 這樣的作法是錯誤的。由於這有重複除以m!根本什麼也不是。。。沒有什麼排列數...spa
正解是隔板法 再次隔板 設當前人數爲 s=m-2*n 那麼其實有將s我的分到n個房間中 且每一個房間總和爲s 也就是說 x1+x2+x3+x4+...=s 這顯然是隔板法了...設計
注意到x可能爲0 因此再補板n-1 空隙 仍是插板n-1個便可。m爲500 用頭想都是高精。C(s+n-1,n-1) 。。。想10min都沒怎麼發現這個模型藏得有點深。3d
約分是必要的 分解質因數再約分 就變成高精乘單精了。rest
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<ctime> #include<cstring> #include<string> #include<ctime> #include<cctype> #include<cstdio> #include<utility> #include<queue> #include<stack> #include<deque> #include<map> #include<set> #include<bitset> #include<vector> #include<algorithm> #include<cstdlib> #define ll long long using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=1010; int s0,s1,s2; int p0[MAXN],p1[MAXN],p2[MAXN]; int b[MAXN],top; int n,m,s,c; inline void insert(int x,int *a) { int s=x; for(int i=2;i*i<=x;++i) while(s%i==0) { s=s/i; ++a[i]; } if(s>1)++a[s]; } inline void mul(int x) { int res=0; for(int i=1;i<=top;++i) { b[i]=b[i]*x; b[i]+=res; res=b[i]/10; b[i]=b[i]%10; } while(res) { b[++top]=res; res=b[top]/10; b[top]=b[top]%10; } } int main() { //freopen("1.in","r",stdin); n=read();m=read(); if(m<2*n){puts("0");return 0;} s=m-2*n+n-1;c=n-1;//求 C(s,c); for(int i=2;i<=s;++i)insert(i,p0); for(int i=2;i<=c;++i)insert(i,p1); for(int i=2;i<=s-c;++i)insert(i,p2); b[++top]=1; for(int i=2;i<=s;++i) { p0[i]=p0[i]-p1[i]-p2[i]; while(p0[i]) { --p0[i]; mul(i); } } for(int i=top;i>=1;--i)printf("%d",b[i]); return 0; }
LINK:免費餡餅code
咕了 這麼長時間了 也該寫寫了... 看起來很顯然是dp 可是還要輸出方案...(那也很水
第一次寫狀態轉移寫錯了 ,驚了 瞎寫了一個狀態轉移..感受不太對..固然f[i][j]表示第i秒到了第j個位置的最大價值 f[i][j]=max(f[i-1][j-1],f[i-1][j-2]...)而後 餡餅的話開vector記錄下來,到達這個位置就累加上價值便可。
有一個坑點是 對於一個餡餅 降低高度爲 h-1 題目中說道 剛好在某一秒末和人相遇才行也就是 h-1%v!=0的都不能要。還有一個坑點是 方案要從最後一個餡餅開始找而不是最後一秒開始...
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define R register #define db double #define max(x,y) ((x)>(y)?(x):(y)) using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=110,maxn=2010; int n,m,cnt,maxx,ans; int st[MAXN],top; struct wy { int s,x,v,p; }t[maxn]; int f[maxn][MAXN];//f[i][j]表示第i秒在x這個位置所能得到的最大分數 int w[maxn][MAXN]; vector<int>g[maxn]; inline int abs(int x){return x>0?x:-x;} inline void get_path(int x,int y) { if(!x)return; st[++top]=-(w[x][y]-y); get_path(x-1,w[x][y]); } int main() { //freopen("1.in","r",stdin); n=read();m=read(); int s,x,v,p,h=m;--h; while(scanf("%d",&s)==1) { x=read();v=read();p=read(); if(h%v!=0)continue; t[++cnt]=(wy){s,x,v,p}; int st=s+h/v; g[st].push_back(cnt); maxx=max(maxx,st); } memset(f,0xcf,sizeof(f)); f[0][(n>>1)+1]=0; for(int i=1;i<=maxx;++i) { for(int j=1;j<=n;++j) { for(int k=max(1,j-2);k<=min(n,j+2);++k) { if(f[i][j]<f[i-1][k]) { f[i][j]=f[i-1][k]; w[i][j]=k; } } } for(int k=0;k<(int)g[i].size();++k) { int r=g[i][k]; f[i][t[r].x]+=t[r].p; } } for(int i=1;i<=n;++i)ans=max(ans,f[maxx][i]); printf("%d\n",ans); for(int i=1;i<=maxx;++i) { for(int j=1;j<=n;++j) { if(f[i][j]==ans) { get_path(i,j); for(int k=top;k>=1;--k)printf("%d\n",st[k]); return 0; } } } return 0; }
update :其實這個也能夠不用vector存咱們利用排序後時間從大到小的順序便利整個數組便可 省掉空間和時間...
LINK:字符合並
早就想寫這道題了 受不了了 這道題 是水題..我堅信。(而後想了30min 被打臉...
仍是 字符串之間進行合併 值得一提的是此次只有01串 每k個字符能夠合成一個字符 存在一個命題是 若是(n-1)%(k-1)==0的話那麼則有 最後合併剩下一個字符 (我也不知道是怎麼證實的..
首先仍是設計狀態吧 反正是區間dp 轉移着實有點困難 但在我堅持不懈的努力之下 仍是成功的進行轉移了 可是不知道對不對 感受正確性仍是有的..
f[i][j][k]表示 由i到j狀態爲k的最大 代價 那麼轉移就是區間dp 而後 枚舉斷點 惟一不一樣的是還須要枚舉左邊狀態s1 右邊狀態s2 而後merge一下便可 merge有點難寫 可是仔細思考仍是能夠O(1)的...
可是這樣的複雜度是n^3*2^k*2^k=n^3*4^k; 顯然過不了1e12 。
這裏先放暴力(我不知道對不對 不想交):發現暴力是瞎寫的 不放了
固然 我以爲這個merge寫的還算很精闢/cy.(精闢錘子 寫錯了。
考慮優化一個比較顯然的地方是每次咱們枚舉狀態的時候其實沒必要要枚舉到1<<(k-1) 由於對於一個區間來講其固定的狀態大小是存在的 (n-1)%(k-1)+1其實就是這個東西了...每8次一循環每一個循環的複雜度是2^1-1+2^2-1+...2^7-1加起來是2^8那麼這樣其實複雜度驟降8倍..
還有一個不太明顯的優化是 進行狀態合併的時候 若是沒有合成 也就是不到k個字符的合成 左邊合成和右邊合成其實都是等效的 因此咱們能夠省掉右邊的合併欽定左邊進行合併便可。
那麼就是 咱們只在意右邊合成了1或者0 至於更多的能夠無論交給左邊去合成便可。這樣複雜度降爲n^3*2^k/8 能夠calc一下 發現能夠過了.
這樣對於左邊的狀態咱們仍是能夠利用(n-1)%(k-1)這個東西來剪枝。
那麼這道題也就作完了 我看了一眼書才發現的解法 我也沒想到第二個優化 可能腦子有點亂..之後dp的時候要清醒 別看書或看題解..這點小優化仍是能夠想出來的我以爲。
一直wa 發現是合併的時候 沒有判斷準確合併的大小和長度 不是隨便合併的 0000和1能夠合併可是狀態得本身看 有的時候0 可能表明着0000什麼的我忽略了這一點。
固然 得開long long 題目描述不清楚 固然所有開long long會T (我真不容易寫一道題。注意不要全開long long 常數是int的兩倍 因而把for裏的改爲int就過了。
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define R register #define db double #define max(x,y) ((x)>(y)?(x):(y)) using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=301,maxn=8; ll n,k,ans; int a[MAXN],p[1<<maxn]; int s[1<<maxn]; ll f[MAXN][MAXN][1<<maxn]; //f[i][j][k] 表示由區間i到區間j合成後狀態爲k的最大值 signed main() { //freopen("1.in","r",stdin); n=read();k=read(); memset(f,0xcf,sizeof(f)); for(int i=1;i<=n;++i)a[i]=read(),f[i][i][a[i]]=0; for(int i=0;i<(1<<k);++i) s[i]=read(),p[i]=read(); for(int len=2;len<=n;++len) { for(int i=1;i<=n-len+1;++i) { int j=i+len-1; for(int l=i;l<j;++l) { int len2=j-l; if((len2-1)%(k-1))continue; int len1=l-i+1; len1=(len1-1)%(k-1)+1; for(int s1=0;s1<(1<<len1);++s1) { if(f[i][l][s1]<0)continue; if(f[l+1][j][0]>=0) { int state=s1<<1; if(len1==k-1) f[i][j][s[state]]=max(f[i][j][s[state]],f[i][l][s1]+f[l+1][j][0]+p[state]); else f[i][j][state]=max(f[i][j][state],f[i][l][s1]+f[l+1][j][0]); } if(f[l+1][j][1]>=0) { int state=s1<<1|1; if(len1==k-1) f[i][j][s[state]]=max(f[i][j][s[state]],f[i][l][s1]+f[l+1][j][1]+p[state]); else f[i][j][state]=max(f[i][j][state],f[i][l][s1]+f[l+1][j][1]); } } } } } for(int i=0;i<(1<<(k-1));++i) ans=max(ans,f[1][n][i]); printf("%lld\n",ans); return 0; }
LINK:分數規劃生成樹
其實就是想讓咱們找出一個最小的生成樹罷了,直接prim會比克魯斯卡爾快一點。注意這裏須要二分一下比值由於咱們很差直接求出這個比值。
因此考慮先二分,而後權值就有了咱們想辦法讓mid減少的那個方式生成樹便可。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define INF 1000000000 #define ll long long #define db double #define EPS 1e-4 #define mp make_pair #define F first #define S second using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=1010; int n; struct wy { int x,y,z; }t[MAXN]; int vis[MAXN]; db a[MAXN][MAXN],d[MAXN]; priority_queue<pair<db,int> > q; inline int abs(int x){return x<0?-x:x;} inline db dis(int x,int y) { return sqrt(1.0*(t[x].x-t[y].x)*(t[x].x-t[y].x)+1.0*(t[x].y-t[y].y)*(t[x].y-t[y].y)); } inline int check(db w) { db ans=0; for(int i=1;i<=n;++i)d[i]=INF*1.0,vis[i]=0; q.push(mp(0,1)); while(q.size()) { int x=q.top().S; if(vis[x]) { q.pop(); continue; } ans=ans-q.top().F; vis[x]=1; for(int i=1;i<=n;++i) { if(vis[i])continue; db dd=abs(t[x].z-t[i].z)-a[x][i]*w; if(d[i]>dd) { d[i]=dd; q.push(mp(-d[i],i)); } } } if(ans<=0)return 1; return 0; } int main() { //freopen("1.in","r",stdin); n=read(); for(int i=1;i<=n;++i) { int x,y,z; x=read();y=read();z=read(); t[i]=(wy){x,y,z}; } for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) a[i][j]=a[j][i]=dis(i,j); db l=0,r=100; while(l+EPS<r) { db mid=(l+r)/2; if(check(mid))r=mid; else l=mid; } printf("%.3lf",l); return 0; }
LINK:pigs有點神奇的題目 看起來很複雜 但其實我還真不會 我有一個作法是拆點而後對於每一個人都作一次最大流 可是仍是沒法實現豬交換的時候的合法性。
作法比較強大 是這樣的咱們很難完成在存在牛的點的狀況下實現牛之間的交換由於考慮這個順序比較難以控制 可能較早的點會用較晚的點的邊因此這很很差寫,咱們不妨不建牛點 把牛放到一塊而後表示牛能夠任意互換,這樣就不會出現上述狀況了。綜上咱們 每次都將一堆牛直接連向一我的 若是下次還有人連相同的牛的話就把上次連的人連向當前這我的便可。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define INF 1000000000 #define ll long long #define db double #define mp make_pair using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=1010; int n,m,S,T,ans,len=1,t,h; int a[MAXN],b[MAXN]; int lin[MAXN],nex[MAXN*100<<1],ver[MAXN*100<<1],e[MAXN*100<<1]; int q[MAXN],vis[MAXN],cur[MAXN]; inline void add(int x,int y,int z) { ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z; ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0; } inline int bfs() { h=t=0; for(int i=1;i<=T;++i)vis[i]=0,cur[i]=lin[i]; q[++t]=S;vis[S]=1; while(h++<t) { int x=q[h]; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(!e[i]||vis[tn])continue; vis[tn]=vis[x]+1; q[++t]=tn; if(tn==T)return 1; } } return 0; } inline int dinic(int x,int flow) { if(x==T)return flow; int rest=flow,k; for(int i=cur[x];i&&rest;i=nex[i]) { int tn=ver[i]; cur[x]=i; if(vis[tn]==vis[x]+1&&e[i]) { k=dinic(tn,min(flow,e[i])); if(!k){vis[tn]=0;continue;} e[i]-=k;e[i^1]+=k;rest-=k; } } return flow-rest; } int main() { //freopen("1.in","r",stdin); m=read();n=read(); S=n+1;T=S+1; for(int i=1;i<=m;++i)a[i]=read(); for(int i=1;i<=n;++i) { int x=read(),cnt=0; for(int j=1;j<=x;++j) { int y=read(); if(b[y])add(b[y],i,INF); else cnt+=a[y]; b[y]=i; } x=read(); add(S,i,cnt); add(i,T,x); } int flow=0; while(bfs())while((flow=dinic(S,INF)))ans+=flow; printf("%d\n",ans); return 0; }
LINK:足球積分 看起來是個貪心。其實應該就是貪心了。很簡單對於求最大值咱們能贏就贏不要平局由於贏得話比平局得分高 。
輸的話恰好相反 分類討論一下便可。想了一下求最小值還真的有很大的難度 思考良久發現把全部狀況搞出來取最小值便可。
很不錯的貪心 雖然wa了不少次 下次在提交以前應該手玩一些數據纔對。細節 有點ex 不過剩下的就沒什麼了。
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<cctype> #include<algorithm> #include<cstdlib> #include<queue> #include<stack> #include<set> #include<bitset> #include<vector> #include<map> #include<deque> #include<utility> #define INF 1000000010 #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define mp make_pair #define ll long long using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const ll MAXN=100010,maxn=MAXN<<1; ll x,y,n; ll ans,ans1; signed main() { //freopen("1.in","r",stdin); while(scanf("%d%d%d",&x,&y,&n)==3) { ans=ans1=0; ll xx=x,yy=y,nn=n; if(n==1) { if(x>y)ans=ans1=3; if(x==y)ans=ans1=1; printf("%lld %lld\n",ans,ans1); continue; } //先求最大值 ll w=n-1; ll v=min(w,x); ans+=v*3; w-=v; x-=v; if(x>y)ans+=3; if(x==y)++ans; ans+=w; printf("%lld ",ans); //再求最小值 if(xx>yy) { ans1+=3; --nn; v=min(yy,nn); nn-=v; ans1+=nn; printf("%lld\n",ans1); continue; } --nn; if(xx==yy) { if(nn>=3&&yy>=3) { ans1+=3; v=min(yy,nn); nn-=v; ans1+=nn; printf("%lld\n",ans1); } else { ++ans1; ans1+=nn; printf("%lld\n",ans1); } } else//對於 xx<yy 能夠考慮把全部狀況表示出來取min { ll w1=3,w2=1,w3=0; w1=w1+(nn-min(nn,yy)); yy-=xx; w2=w2+(nn-min(nn,yy)); --yy; w3=w3+(nn-min(nn,yy)); ans1=min(w1,w2); ans1=min(ans1,w3); printf("%lld\n",ans1); } } //cout<<w1<<' '<<w2<<' '<<w3<<endl; return 0; }
LINK:揹包的方案數問題。 求不適用第一個物品且裝滿揹包的方案數 再求不用第二個物品的方案數 一直求到第n個?
一個比較顯然的思路是暴力 n^2m的暴力 考慮優化這個過程。考慮 咱們每次把有用的東西保存下來。也就是說 咱們先對總體進行一次01揹包方案數 而後 想辦法求出第一個除去第一個物品的方案數 觀察 把dp式加法換成減法便可。考慮一下實際的意義。
咱們先廣義的分析:作揹包 和 物品的順序無關 因此咱們能夠想象成第一個物品是最後一個加進去的 因此能夠看出 這樣的作法顯然正確。
狹義的想:這很顯然。
當時我寫的無腦暴力 仍是保存一下吧 。
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<algorithm> #include<ctime> #include<map> #include<vector> #include<stack> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=1014; int n,m; int w[maxn],f[10007],ans=0; int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;i++)w[i]=read(),ans+=w[i]; f[0]=1; for(int k=1;k<=n;k++) { memset(f,0,sizeof(f)); f[0]=1; for(int i=1;i<=n;i++) { if(ans-w[i]<m)break; for(int j=m;j>=w[i];j--) { if(i==k)continue; f[j]=(f[j]%maxn+f[j-w[i]]%maxn)%maxn; } } printf("%d ",f[m]%maxn); if(k==n)printf("\n"); } return 0; }
這是 很順利的 倒序揹包清空一下便可。
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000010 #define ll long long #define mp(x,y) make_pair(x,y) #define un unsigned #define db double #define EPS 1e-5 #define mod 1014 using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=10010; int n,m; int a[MAXN],f[MAXN],w[MAXN]; int main() { //freopen("FILE.in","r",stdin); //freopen("FILE.out","w",stdout); n=read();m=read(); f[0]=1; for(int i=1;i<=n;++i)a[i]=read(); for(int i=1;i<=n;++i) for(int j=m;j>=a[i];--j) f[j]=(f[j]+f[j-a[i]])%mod; //for(int i=1;i<=m;++i)cout<<f[i]<<endl; for(int i=1;i<=n;++i) { if(m<a[i]){printf("%d\n",f[m]);continue;} for(int j=0;j<=m;++j)w[j]=f[j]; for(int j=a[i];j<=m;++j)f[j]=(f[j]-f[j-a[i]])%mod; printf("%d ",((f[m]+mod)%mod)); for(int j=0;j<=m;++j)f[j]=w[j]; } return 0; }
LINK:最大速度 中級搜索。 這題 搜索起來比較麻煩。
因爲到達每一個點還有方向考慮把方向也存起來 考慮dij 開跑 可是連續轉兩次也算掉頭 因此還難免記錄上次左轉仍是右轉。
注意 大根堆別寫錯 方向別搞錯 預處理要仔細 dij 換成spfa 咱們發現 有狀態都是0 可是一個0狀態能更新一個0狀態 因此只能spfa了..
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000010 #define ll long long #define mp(x,y) make_pair(x,y) #define un unsigned #define db double #define EPS 1e-5 #define mod 1014 using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=31; int st,en,op,s1,s2,vv,n,m,cnt,ans; int dx[5]={0,1,-1,0,0}; int dy[5]={0,0,0,1,-1}; int f[MAXN][MAXN][5],fa[MAXN*MAXN]; int vis[MAXN][MAXN][5],id[MAXN][MAXN]; int d[5][5][2],v[5][5],g[5][5]; struct wy { int x,y,op; int v,pre; int friend operator <(wy a,wy b) { return a.v<b.v; } }; char a[MAXN][MAXN]; priority_queue<wy> q; inline int getfather(int x){return x==fa[x]?x:fa[x]=getfather(fa[x]);} inline void bfs() { while(q.size()) { wy s=q.top();q.pop(); //if(vis[s.x][s.y][s.op])continue; //vis[s.x][s.y][s.op]=1; for(int i=1;i<=4;++i) { int xx=s.x+d[s.op][i][0]; int yy=s.y+d[s.op][i][1]; if(xx<1||yy<1||xx>n||yy>m)continue; if(a[xx][yy]=='.')continue; int w=max(0,s.v+v[s.op][i]); if(g[s.op][i]==s.pre&&s.pre>0)w=0; if(f[xx][yy][i]<w) { f[xx][yy][i]=w; q.push((wy){xx,yy,i,w,g[s.op][i]}); } } } } int main() { //freopen("1.in","r",stdin); n=read();m=read();vv=read(); memset(f,0xcf,sizeof(f)); for(int i=1;i<=n;++i) { scanf("%s",a[i]+1); for(int j=1;j<=m;++j) { id[i][j]=++cnt;fa[cnt]=cnt; if(a[i][j]!='.'&&a[i][j]!='#'&&a[i][j]!='F') { if(a[i][j]=='E')op=1; if(a[i][j]=='W')op=2; if(a[i][j]=='N')op=3; if(a[i][j]=='S')op=4; st=i,en=j; } if(a[i][j]=='F')s1=i,s2=j; } } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { if(a[i][j]=='.')continue; for(int k=1;k<=4;++k) { int x=i+dx[k]; int y=j+dy[k]; if(x<1||y<1||x>n||y>m)continue; if(a[x][y]=='.')continue; int xx=getfather(id[x][y]); int yy=getfather(id[i][j]); fa[xx]=yy; } } if(getfather(fa[id[st][en]])!=getfather(fa[id[s1][s2]])) { puts("-1");return 0; } f[st][en][op]=vv; d[1][1][0]=0;d[1][1][1]=1;v[1][1]=1;g[1][1]=0; d[1][2][0]=0;d[1][2][1]=0;v[1][2]=-INF;g[1][2]=-1; d[1][3][0]=0;d[1][3][1]=0;v[1][3]=-35;g[1][3]=1;//向左 d[1][4][0]=0;d[1][4][1]=0;v[1][4]=-40;g[1][4]=2;//向右 d[2][1][0]=0;d[2][1][1]=0;v[2][1]=-INF;g[2][1]=-1; d[2][2][0]=0;d[2][2][1]=-1;v[2][2]=1;g[2][2]=0; d[2][3][0]=0;d[2][3][1]=0;v[2][3]=-40;g[2][3]=2; d[2][4][0]=0;d[2][4][1]=0;v[2][4]=-35;g[2][4]=1; d[3][1][0]=0;d[3][1][1]=0;v[3][1]=-40;g[3][1]=2; d[3][2][0]=0;d[3][2][1]=0;v[3][2]=-35;g[3][2]=1; d[3][3][0]=-1;d[3][3][1]=0;v[3][3]=1;g[3][3]=0; d[3][4][0]=0;d[3][4][1]=0;v[3][4]=-INF;g[3][4]=-1; d[4][1][0]=0;d[4][1][1]=0;v[4][1]=-35;g[4][1]=1; d[4][2][0]=0;d[4][2][1]=0;v[4][2]=-40;g[4][2]=2; d[4][3][0]=0;d[4][3][1]=0;v[4][3]=-INF;g[4][3]=-1; d[4][4][0]=1;d[4][4][1]=0;v[4][4]=1;g[4][4]=0; q.push((wy){st,en,op,vv,-2}); bfs(); for(int i=1;i<=4;++i)ans=max(ans,f[s1][s2][i]); printf("%d\n",ans); return 0; }
LINK:序列遊戲 瘋狂的刷題之中儘可能不看題解TAT。
兩種問題 1 輸出字典序第k小的序列 2 輸出某個全排列 的字典序編號。
也就是兩個問題 恰好互反。詢問有10000次 但序列的長度只有20。
遇到這種序列問題先分析一下數字典序須要什麼東西QuQ 由於沒有性質作題 很難受的。
我想了半天逆序對 但我以爲和逆序對無關關鍵是字典序。值得一提的是這裏序列都是全排列。
先思考一下Q1 無疑 字典序第k小 字典序之和當前數字大小有關 那麼咱們逐位考慮 對於當前位置i 能放i就放 不能放的話考慮 其放哪qwq
逐位考慮有效 若是當前位不行 那就 減少了 屢次階乘的方案 這樣考慮下去便可。
重點是第二問 如何導出 仍是逐位考慮 而後發現 了一些小性質 對於第一個位置 不合法的話咱們把全部對後面的影響都減掉 默認後面所有都是單調遞減的。
再繼續向後面掃若是不是單調遞減的 咱們還須要加回來 而後逐位判斷是否加便可。
#//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define INF 1000000000 #define ll long long #define db double #define pb push_back #define un unsigned using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const ll MAXN=25; ll n,Q,k,ans; char a[2]; ll b[MAXN],fac[MAXN],vis[MAXN]; signed main() { //freopen("1.in","r",stdin); n=read();Q=read(); fac[n+1]=1; for(ll i=n;i;--i)fac[i]=fac[i+1]*(n-i+1); for(ll i=1;i<=Q;++i) { scanf("%s",a+1); if(a[1]=='P') { k=read(); memset(vis,0,sizeof(vis)); for(ll j=1;j<=n;++j) { for(ll m=1;m<=n;++m) { if(vis[m])continue; if(fac[j+1]>=k) { vis[m]=1; b[j]=m; break; } else k-=fac[j+1]; } } for(ll j=1;j<=n;++j)printf("%lld ",b[j]); puts(""); } else { ll flag=0;ans=0; for(ll j=1;j<=n;++j) { b[j]=read(); if(b[j]!=j&&!flag){flag=j;ans+=(b[j]-j+1)*fac[j+1];} } if(!flag){puts("1");continue;} memset(vis,0,sizeof(vis)); for(ll j=1;j<=n;++j) { if(j>flag) { ll w=0; for(ll m=b[j];m<=n;++m) { if(vis[m])continue; ++w; } ans-=(w-1)*fac[j+1]; } vis[b[j]]=1; } printf("%lld\n",ans); } } return 0; }
LINK:在線查詢第k大 在線查詢第k大 每次針對全局找第k大 這個很好寫吧 而後其實就是單點修改了。
我再一次手懶的沒寫splay 直接主席樹水了 我好菜啊 連平衡樹都 碼不出來 /kk
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define INF 1000000000 #define inf 1000000000 #define ll long long #define mod 1000000007 #define db double #define pb push_back #define un unsigned #define l(p) t[p].l #define r(p) t[p].r #define sum(p) t[p].sum using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=100010; int n,id,Q; int a[MAXN],maxx=INF,minn,rt; char b[2]; struct wy { int l,r; int sum; }t[MAXN*30<<1]; inline void insert(int &p,int l,int r,int x,int w) { if(!p)p=++id; if(l==r){sum(p)+=w;return;} int mid=(l+r)>>1; if(x<=mid)insert(l(p),l,mid,x,w); else insert(r(p),mid+1,r,x,w); sum(p)=sum(l(p))+sum(r(p)); } inline int ask(int p,int l,int r,int k) { if(sum(p)<k)return -1; if(l==r)return l; int mid=(l+r)>>1; if(sum(r(p))>=k)return ask(r(p),mid+1,r,k); return ask(l(p),l,mid,k-sum(r(p))); } signed main() { //freopen("1.in","r",stdin); n=read(); for(int i=1;i<=n;++i)a[i]=read(),insert(rt,minn,maxx,a[i],1); Q=read(); for(int i=1;i<=Q;++i) { scanf("%s",b+1); int x=read(),y; if(b[1]=='A') { y=read(); insert(rt,minn,maxx,a[x],-1); a[x]-=y; if(a[x]<=0)continue; insert(rt,minn,maxx,a[x],1); } if(b[1]=='C') { y=read(); insert(rt,minn,maxx,a[x],-1); a[x]+=y; insert(rt,minn,maxx,a[x],1); } if(b[1]=='Q')printf("%d\n",ask(rt,minn,maxx,x)); } printf("%d\n",sum(1)); return 0; }
我靠???我電腦關機了 寫了一堆東西沒了 自閉 3min。
LINK:一個巨難無比的區間dp 寫這個題 整我的都快死了 不過打代碼的 感受仍是挺不錯的。
這道題 我想了一些狀態都是沒法完成一些操做 考慮正解 設f[i][j][k]表示在i到j這個區間前加k個ai珠子的最小代價。
這個狀態是必要的消掉柱子的時候就兩端拼起來就是在某個地方添柱子的 決策 因此這個狀態是必要的 。
而後 值得注意的是消掉柱子咱們只須要判斷消掉中間的一段而後兩端連起來就好了 而後 兩端具體一點是指 1個球和後面的一段 由於區間的決策具備最優性此時枚舉決策一段和一個球能夠近乎當作等效 因此 這樣轉移的dp是正確的。
因爲沒有明顯的遞推關係 因此須要記搜一下。
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define pii pair<ll,ll> #define mk make_pair using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=110; int n,K; int f[MAXN][MAXN][5];//f[i][j][k]表示在i到j這個區間前加k個ai珠子的最小代價 int a[MAXN]; inline int dfs(int l,int r,int k)//描述整個狀態 { if(f[l][r][k]!=-1)return f[l][r][k]; if(l==r)return f[l][r][k]=K-(k+1); if(l>r)return 0; int ans=INF; if(k+1==K)ans=min(ans,dfs(l+1,r,0));//發現能夠消掉 if(k+1<K)ans=min(ans,dfs(l,r,k+1)+1);//原地 加一個球 for(int i=l+1;i<=r;++i) if(a[l]==a[i]) ans=min(ans,dfs(l+1,i-1,0)+dfs(i,r,min(K-1,k+1))); return f[l][r][k]=ans; } int main() { //freopen("1.in","r",stdin); n=read();K=read(); memset(f,-1,sizeof(f)); for(int i=1;i<=n;++i)a[i]=read(); printf("%d\n",dfs(1,n,0)); return 0; } /** * ┏┓ ┏┓+ + * ┏┛┻━━━┛┻┓ + + * ┃ ┃ * ┃ ━ ┃ ++ + + + * ████━████+ * ◥██◤ ◥██◤ + * ┃ ┻ ┃ * ┃ ┃ + + * ┗━┓ ┏━┛ * ┃ ┃ + + + +Code is far away from * ┃ ┃ + bug with the animal protecting * ┃ ┗━━━┓ 神獸保佑,代碼無bug * ┃ ┣┓ * ┃ ┏┛ * ┗┓┓┏━┳┓┏┛ + + + + * ┃┫┫ ┃┫┫ * ┗┻┛ ┗┻┛+ + + + */