1. 程式人生 > 實用技巧 >陝西師範大學acm題解

陝西師範大學acm題解

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;
}