陝西師範大學acm題解
阿新 • • 發佈:2020-09-03
1.目前還沒寫
2
題意:輸入一個矩陣圖,起點到終點路徑值合的最小值。
題解:bfs剪枝,每次更新小值
#include<bits/stdc++.h> #include<string.h> #include<set> #include<cstdio> #include<stdio.h> #include<vector> using namespace std; const int N=2e5+20; const int inf = 0x3f3f3f3f; int ne[4][2]= {{0,-1},{0,1},{-1,0},{1,0}}; pair<int,int>p; int a[350][350],dis[350][350]; typedef long long ll; int main() { int n; cin>>n; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) cin>>a[i][j]; memset(dis,inf,sizeof(dis)); queue<pair<int, int> > q; q.push({1,1}); dis[1][1]=a[1][1]; while(!q.empty()) { pair<int, int> now=q.front(); q.pop(); int x=now.first,y=now.second; for(int i=0; i<4; i++) { int xx=x+ne[i][0],yy=y+ne[i][1]; if(a[xx][yy]==0) continue;if(xx<1||yy<1||xx>n||yy>n) continue; if(dis[xx][yy]!=0&&dis[xx][yy]<dis[x][y]+a[xx][yy]) continue; dis[xx][yy]=dis[x][y]+a[xx][yy]; q.push({xx,yy}); } } if(dis[n][n]==inf) printf("0\n"); else printf("%d\n",dis[n][n]); }
3.
題意:給定長度n,數值範圍1--m,求一個序列,先升後降,其中可以有一個重複的數字。
題解:排列組合,求逆元,快速冪。
#include<bits/stdc++.h> #include<string.h> #include<set> #include<math.h> #include<cstdio> #include<stdio.h> #include<vector> using namespace std; const int N=2e5+200; const int inf = 0x3f3f3f3f; typedef long long ll; const ll mod=998244353; int f[N]; ll n,m; ll qpow(ll a,ll b) { ll res=1; while(b) {if(b&1) res=res*a%mod; a=a*a%mod; b=b>>1;} return res; } void in() { f[0]=1; for(int i=1;i<N;i++) f[i]=f[i-1]*(ll)i%mod; } int main() { in(); int n,m; cin>>n>>m; if(n==2) printf("0\n"); else { ll sum=(n-2)*qpow(2,n-3)%mod*f[m]%mod*qpow(f[m-n+1]*f[n-1]%mod,mod-2)%mod; printf("%lld\n",sum); } }
4.
題意:求某名字前重複的名字有多少
#include<bits/stdc++.h> #include<string.h> #include<set> #include<stdio.h> using namespace std; const int N=1e5+1,mod=3600; typedef long long ll; ll dp[30][30]; int a[150000]; int main() { set<string>q; int n; cin>>n; string b; b="younik"; int ans=0; for(int i=1;i<=n;i++) { string c;cin>>c; if(strcmp(c.c_str(),b.c_str())==0&&ans==0) ans=i;//判斷倆個字串相等 else if(ans==0) q.insert(c); } printf("%d",q.size()+1); }
5.
題意:求x軸上圓的的最少個數覆蓋所有點
題解:一個座位的最左能到和最右能到的圓心邊界點可以通過勾股定理求,然後如果前一個的右界端點>=後一個左界端點,覆蓋這兩個點的圓的半徑<=d就可以滿足(畫個圖可以發現區間∩其實連線長度<三角形最長邊的d長度),所以d半徑的圓一定滿足。然後N^2暴力標記統計就好了。
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<cmath> #include<map> #include<set> #include<cstdio> #include<algorithm> #define debug(a) cout<<#a<<"="<<a<<endl; using namespace std; const int maxn=1e3+100; typedef long long LL; bool vis[maxn]; LL n,d; struct P{ double x,y; }a[maxn]; struct data{ double left,right; }da[maxn]; bool cmp(data A,data B){ return A.right<B.right; } int main(void) { cin.tie(0);std::ios::sync_with_stdio(false); while(cin>>n>>d&&n!=0&&d!=0){ memset(vis,0,sizeof(vis)); bool flag=1; for(LL i=1;i<=n;i++) { cin>>a[i].x>>a[i].y; if(a[i].y>d||a[i].y<-d) flag=0; } for(LL i=1;i<=n;i++){ double mid=sqrt(1.0*d*d-1.0*a[i].y*a[i].y); da[i].left=a[i].x-mid; da[i].right=a[i].x+mid; } sort(da+1,da+1+n,cmp); LL ans=0; for(LL i=1;i<=n;i++){ if(!vis[i]){ vis[i]=true; for(LL j=i+1;j<=n;j++){ if(!vis[j]&&da[i].right>=da[j].left){ vis[j]=true; } } ans++; } } if(flag) cout<<ans<<endl; else cout<<-1<<endl; } return 0; }
6.
題意:求第二短路徑
題解:直接套最短路徑模板,開倆個dis
#include<bits/stdc++.h> #include<string.h> #include<set> #include<cstdio> #include<stdio.h> #include<vector> using namespace std; const int N=2e5+20; const int inf = 0x3f3f3f3f; typedef long long ll; int nn=0,head[N],dis1[N],dis2[N],vis[N]; queue<int>q; struct node { int to,next,v; }m[N]; void add(int a,int b,int c) { m[++nn].next=head[a]; m[nn].to=b; m[nn].v=c; head[a]=nn; } void spfa() { q.push(0); memset(dis1,inf,sizeof(dis1)); memset(dis2,inf,sizeof(dis2)); vis[0]=1; dis1[0]=0; while(!q.empty()) { int e=q.front();q.pop(); vis[e]=0; for(int i=head[e];i!=-1;i=m[i].next) { int to=m[i].to; if(dis1[to]>dis1[e]+m[i].v) { dis2[to]=dis1[to]; dis1[to]=dis1[e]+m[i].v; if(vis[to]==0) {vis[to]=1;q.push(to);} } if(dis2[to]>dis2[e]+m[i].v) { dis2[to]=dis2[e]+m[i].v; if(vis[to]==0) {vis[to]=1;q.push(to);} } if (dis1[to]<dis1[e]+m[i].v&&dis2[to]>dis1[e]+m[i].v) { dis2[to] = dis1[e] + m[i].v; if (!vis[to]) vis[to]=1,q.push(to); } } } } int main() { int n,t; memset(head,-1,sizeof(head)); cin>>n>>t; for(int i=0;i<t;i++) { int a,b,c;cin>>a>>b>>c; add(a,b,c); add(b,a,c); } spfa(); printf("%d\n",dis2[n-1]); }
7.
題意:01揹包,多了條件,可以重複吃,得到的快樂值會少
題解:把重複吃的全部填加進去,開一維dp
#include<bits/stdc++.h> #include<string.h> #include<set> #include<cstdio> #include<stdio.h> #include<vector> using namespace std; const int N=2e5+20; const int inf = 0x3f3f3f3f; int dp[10010],nn=-1; int w[N],v[N]; typedef long long ll; int main() { int n,m;cin>>n>>m; for(int i=0;i<n;i++) { int a,b;cin>>a>>b; w[++nn]=b; v[nn]=a; int s=1; while(a>s) { w[++nn]=b; v[nn]=a-s; s*=2; } } for(int i=0;i<=nn;i++) { for(int j=m;j>=w[i];j--) { dp[j]=max(dp[j-w[i]]+v[i],dp[j]); } } printf("%d\n",dp[m]); return 0; }