題目過水,直接暴力搞過去,代碼就不貼了。
但我TM竟然有個地方SB了,調了半天才發現輸入有問題:node
scanf("%d%d%d",&x,&y,&t[x][y]);//這是我原來的寫法.....
先處理出全部知足條件的點,而後在上面跑死了的\(spfa\)便可。
注意這裏咱們不是直接去找與終點相連的點,由於這樣會漏掉一些點(別問我怎麼知道的)。
因此咱們能夠用到不了終點的點去跟新其它點便可。ios
\(Code:\)算法
const int N=2e5+5; vector<int>G1[N],G2[N]; //G1正圖 G2反圖 bool T[N],f[N]; int n,m,x,y,s,t,d[N]; queue<int>q; inline void bfs() { q.push(t);T[t]=f[t]=1; while(!q.empty()) { int x=q.front();q.pop(); for(rg int i=0;i<G2[x].size();++i) { int v=G2[x][i]; if(!T[v]) T[v]=f[v]=1,q.push(v); } } for(rg int i=1;i<=n;++i) if(!T[i]) for(rg int j=0;j<G2[i].size();++j) { int v=G2[i][j]; if(f[v]) f[v]=0; } while(!q.empty()) q.pop(); q.push(s);memset(d,0x3f,sizeof d);d[s]=0; while(!q.empty()) { int x=q.front();q.pop(); for(rg int i=0;i<G1[x].size();++i) { int v=G1[x][i]; if(f[v] && d[v]>d[x]+1) { d[v]=d[x]+1; q.push(v); } } } }
我最開始還覺得要打高精度,其實能夠用秦九韶算法來解決。
這個算法能夠將一元\(n\)次多項式的求值問題轉化爲\(n\)個一次式的算法,而後……本身看度娘吧
總之,這個算法可讓咱們在\(O(nm)\)的時間內解決該問題。(過程當中能夠隨便膜一個數如192*****來簡化運算)app
\(Code:\)優化
#include<cstdio> #include<vector> using namespace std; #define int long long const int p=19260817; int n,m,a[105]; vector<int>Ans; inline int read()//騷氣讀入 { int f=1,x=0;register char c=getchar(); while(c>'9' || c<'0') {if(c=='-') f=-1;c=getchar();} while(c>='0' && c<='9') x=((x<<3)+(x<<1)+(c^'0'))%p,c=getchar(); return x*f%p;//記得取膜 } signed main() { n=read(),m=read(); for(int i=0;i<=n;++i) a[i]=read(); for(int i=1;i<=m;++i) { int ans=0; for(int j=n;j>=1;--j) ans=(ans+a[j])*i%p; ans=(ans+a[0])%p; if(!ans) Ans.push_back(i); } printf("%lld\n",(int)Ans.size()); for(int i=0;i<(int)Ans.size();++i) printf("%lld\n",Ans[i]); return 0; }
巨水的模擬,貼一下代碼就好了~~this
\(Code:\)spa
#include<cstdio> using namespace std; const int N=205; int n,na,nb,a[N],b[N],c[5][5],cnta,cntb; //0表示「剪刀」,1表示「石頭」,2表示「布」,3表示「蜥蜴人」, 4表示「斯波克 int main() { scanf("%d%d%d",&n,&na,&nb); for(int i=1;i<=na;++i) scanf("%d",&a[i]); for(int i=1;i<=nb;++i) scanf("%d",&b[i]); c[1][0]=c[2][1]=c[0][2]=c[0][3]=c[1][3]=c[2][4]=c[3][4]=c[3][2]=c[4][0]=c[4][1]=1; for(int i=1;i<=n;++i) { int A=i%na,B=i%nb; if(!A) A=na; if(!B) B=nb; // printf("%d %d\n",a[A],b[B]); cnta+=c[a[A]][b[B]],cntb+=c[b[B]][a[A]]; // printf("cnt:%d %d\n",cnta,cntb); } printf("%d %d",cnta,cntb); return 0; }
直接 \(O(n^2)\) 暴力枚舉是確定過不了的,要想一些奇技淫巧來優化。code
要求\(u,v\)之間距離爲\(1\),又是在樹上,那麼它們之間必然有\(1\)箇中轉點。因而咱們能夠枚舉該點。get
但\(n\)的範圍巨大,怎麼能高效地跟新答案呢?這裏有一個神奇的公式:string
設 \(S = \sum_{i=1}^n a_i\) , 則有
\(( (S - a_1) + (S - a_2) + \cdots + (S - a_n) ) \times 2 = (a_1+a_2+ \cdots +a_{n-1}+a_n)^2 - (a_1^2+a_2^2+ \cdots +a_{n-1}^2+a_n^2)\)
由於咱們加的是雙向邊,因此對於一個節點\(x\),與它相連的全部點之間均可以互相構成聯合權值
將其表示出來:
\(Code:\)
#include<cstdio> #include<vector> #include<algorithm> #define rg register #define ll long long struct ios{ template<typename TP> inline ios operator >> (TP &x) { TP f=1;x=0;rg char c=getchar(); for(;c>'9' || c<'0';c=getchar()) if(c=='-') f=-1; for(;c>='0' && c<='9';c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); x*=f; return *this; } template<typename TP> inline ios operator << (TP x) { char s[66];rg int cnt=0; if(!x) putchar('0'); if(x<0) x=-x,putchar('-'); while(x) ++cnt,s[cnt]=x%10+'0',x/=10; while(cnt) putchar(s[cnt]),--cnt; return *this; } inline ios operator << (char x) { putchar(x); return *this; } }io; const int N=2e5+5; std::vector<int>G[N]; const int p=10007; int n,a,b,w[N],ans,sum; int main() { io>>n; for(rg int i=1;i<n;++i) { io>>a>>b; G[a].push_back(b),G[b].push_back(a); } for(rg int i=1;i<=n;++i) io>>w[i]; // for(rg int i=1;i<=n;++i) io<<w[i]<<' '; // io<<'\n'; /*--------------------------以某個節點爲中轉點的聯合權值之和等於權值和的平方減去權值的平方和----------------------*/ for(rg int i=1;i<=n;++i) { int max_1=0,max_2=0; int he=0,pf=0; for(int k=0;k<(int)G[i].size();++k) { int v=G[i][k]; // io<<i<<' '<<G[i].size()<<' '<<k<<' '<<v<<'\n'; if(w[v]>max_1) max_2=max_1,max_1=w[v]; else if(w[v]>max_2) max_2=w[v]; he=(he+w[v])%p,pf=(pf+w[v]*w[v])%p; } he=he*he%p; // io<<'h'<<'h'<<max_1<<' '<<max_2<<'\n'; ans=std::max(ans,max_1*max_2); sum=(sum+he-pf+p)%p;//注意he-pf可能爲負數 } io<<ans<<' '<<sum; return 0; }
很顯然能夠看出,這題是\(DP\)(求最優解,數據範圍比較大,還不能貪心,除了\(DP\),還真就沒有作法了)
\(Code:\)
#include<cstdio> #include<algorithm> #include<cmath> #define rg register #define ll long long #define cg c=getchar() using namespace std; struct ios{ template<typename TP> inline ios operator >> (TP &x) { TP f=1;x=0;rg char cg; for(;c>'9' || c<'0';cg) if(c=='-') f=-1; for(;c>='0' && c<='9';cg) x=(x<<3)+(x<<1)+(c^'0'); x*=f; return *this; } template<typename TP> inline ios operator << (TP x) { char s[66];rg int cnt=0; if(x<0) x=-x,putchar('-'); if(!x) putchar('0'); while(x) s[++cnt]=x%10+'0',x/=10; while(cnt) putchar(s[cnt--]); return *this; } inline ios operator << (char s) { putchar(s); return *this; } }io; const int N=1e4; const int M=1e3; const int inf=0x3f3f3f3f; int n,m,k,cnt=1; struct node{ int x,y; }a[N]; struct Node{ int pos,L,H; inline bool operator < (const Node b) const { return pos<b.pos; } }g[N]; int dp[N][M],vis[N][M]; int main() { io>>n>>m>>k; for(rg int i=0;i<n;++i) io>>a[i].x>>a[i].y; for(rg int i=1;i<=k;++i) { io>>g[i].pos>>g[i].L>>g[i].H; for(int j=1;j<=g[i].L;++j) vis[g[i].pos][j]=1; for(int j=g[i].H;j<=m;++j) vis[g[i].pos][j]=1; } sort(g+1,g+k+1); //io<<'h'<<'h'<<'h'<<'\n'; for(rg int i=1;i<=n;++i) for(rg int j=1;j<=m;++j) dp[i][j]=inf; for(rg int i=1;i<=n;++i) { // io<<'h'<<'h'<<'h'<<'\n'; int L=1,R=m; if(g[cnt].pos==i) L=g[cnt].L+1,R=g[cnt].H-1,++cnt; // if(i==5) io<<L<<' '<<R<<'\n'; int x=a[i-1].x,y=a[i-1].y; for(rg int j=L;j<=R;++j) { if(j==m) { for(rg int l=1;l<=m;++l) { if(!vis[i-1][l]) { int w=ceil(1.0*(m-l)/x); if(j==l) w=1; dp[i][j]=min(dp[i][j],dp[i-1][l]+w); } } continue; } // if(i==5) io<<j+y<<' '<<y<<'\n'; if(j+y<=m && !vis[i-1][j+y]) dp[i][j]=min(dp[i][j],dp[i-1][j+y]); int w=j/x; for(rg int l=1;l<=w;++l) if(j-x*l>0 && !vis[i-1][j-x*l]) dp[i][j]=min(dp[i][j],dp[i-1][j-x*l]+l); } // io<<'h'<<'h'<<'h'<<'\n'; } int ans=inf; // for(int i=m;i>=0;--i) // // for(int i = 0; i <= n; ++i) // { // // for (int j = 0; j <= m; ++j) // for(int j=0;j<=n;++j) // { // if(dp[j][i]==inf) io<<'*'<<' '; // else io<<dp[j][i]<<' '; // } // io<<'\n'; // } for(rg int i=1;i<=m;++i) ans=min(ans,dp[n][i]); if(ans==inf) { io<<0<<'\n'; for(rg int i=1;i<=k;++i) { int p=g[i].pos; for(rg int j=1;j<=m;++j) { if(dp[p][j]!=inf) break; if(j==m) { io<<i-1<<'\n'; return 0; } } } } io<<1<<'\n'<<ans; return 0; }
然鵝你發現這個達不到上界的\(O(nm^2)\)的\(DP\)只能水\(80\)分。(不過聯賽時有\(80\)分也不錯了)
那該如何優化呢?
咱們發現,小鳥每次上升屢次,但只能降低一次(保證不超邊界時)。
上升屢次,不就至關因而多重揹包嗎?
那麼降低一次,就能夠看作\(01\)揹包。
有了這個思路,咱們就能夠成功地把複雜度將爲\(O(nm)\)了
\(Code:\)
#include<cstdio> #include<cstring> #include<algorithm> #define rg register #define ll long long #define cg c=getchar() using namespace std; struct ios{ template<typename TP> inline ios operator >> (TP &x) { TP f=1;x=0;rg char cg; for(;c>'9' || c<'0';cg) if(c=='-') f=-1; for(;c>='0' && c<='9';cg) x=(x<<3)+(x<<1)+(c^'0'); x*=f; return *this; } template<typename TP> inline ios operator << (TP x) { char s[66];rg int cnt=0; if(x<0) x=-x,putchar('-'); if(!x) putchar('0'); while(x) s[++cnt]=x%10+'0',x/=10; while(cnt) putchar(s[cnt--]); return *this; } inline ios operator << (char s) { putchar(s); return *this; } }io; const int N=1e4+5; const int M=1e3+5; const int inf=0x3f3f3f3f; int n,m,k; struct node{ int x,y; }a[N]; int dp[N][M<<1],vis[N],L[N],R[N]; int main() { // freopen("1.in","r",stdin); io>>n>>m>>k; for(rg int i=1;i<=n;++i) io>>a[i].x>>a[i].y,L[i]=1,R[i]=m; for(rg int i=1;i<=k;++i) { int a,b,c;io>>a>>b>>c; vis[a]=1,L[a]=b+1,R[a]=c-1; } memset(dp,0x3f,sizeof dp); for(rg int i=1;i<=m;++i) dp[0][i]=0; for(rg int i=1;i<=n;++i) { int x=a[i].x,y=a[i].y; for(rg int j=x+1;j<=m+x;++j) dp[i][j]=min(dp[i-1][j-x]+1,dp[i][j-x]+1); for(rg int j=m+1;j<=m+x;++j) dp[i][m]=min(dp[i][m],dp[i][j]); for(rg int j=1;j+y<=m;++j) dp[i][j]=min(dp[i][j],dp[i-1][j+y]); // io<<i<<' '<<L<<' '<<R<<'\n'; for(rg int j=1;j<=L[i]-1;++j) dp[i][j]=inf; for(rg int j=R[i]+1;j<=m;++j) dp[i][j]=inf; } int ans=inf; // io<<inf<<'\n'; // for(int i=m;i>=0;--i) // // for(int i = 0; i <= n; ++i) // { // // for (int j = 0; j <= m; ++j) // for(int j=0;j<=n;++j) // { // if(dp[j][i]==inf) io<<'*'<<' '; // else io<<dp[j][i]<<' '; // } // io<<'\n'; // } for(rg int i=1;i<=m;++i) ans=min(ans,dp[n][i]); if(ans>=inf) { io<<0<<'\n'; int i,j; for(i=n;i>=1;--i) { for(j=1;j<=m;++j) { if(dp[i][j]<inf) break; } if(j<=m) break; } ans=0; for(int j=1;j<=i;++j) if(vis[j]) ++ans; io<<ans; } else io<<1<<'\n'<<ans; return 0; }