2020hdu多校round3 部分题解(1004,1005,1007,1009)清题中

1004

由于是相邻的数进行合并,很自然的想到了前缀和。这里dp[i]记录到i为止可以整除的整数。最初是超时了,后来剪了下枝就过了。

#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int dp[1000005]={0};
int dis[10000005]={0};
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int x,y;
        memset(dp,0,sizeof(dp));
        memset(dis,0,sizeof(dis));
        cin>>x>>y;
        for(int j=1;j<=x;j++){
            scanf("%d",&a[j]);
            if(a[j]%y!=0)
            a[j]=a[j]%y;
            else
            a[j]=y;
            dis[j]=dis[j-1]+a[j];
        }
        int maxx=0;
        int p=0;
        for(int j=1;j<=x;j++){
            for(int m=p;m<j&&dis[j]-dis[m]>=y;m++){
                int w=dis[j]-dis[m];
                if(w%y==0){
                    dp[j]=max(dp[j],dp[m]+1);
                }
                
            } 
        dp[j]=max(dp[j],dp[j-1]);
        if(dp[j]>maxx){
            maxx=dp[j];
            p=j;
        }
    }
     printf("%d\n",dp[x]);
}
    return 0;
} 

1009

好吧,我是没懂为什么数组和堆会超时,而队列就过了。反正队友NB就对了。

#include<bits/stdc++.h>
using namespace std;
vector<int>que;
vector<int>kuo;
int main(){
    int n;
    string s;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s;
        que.clear();
        kuo.clear();
        int flag=0;
        int l=0;
        int r=0;
        int h=s.length();
        for(int j=0;j<h;j++){
            if(s[j]=='('){
                kuo.push_back(j);
            }
            else if(s[j]=='*'){
                que.push_back(j);
            }
            else if(s[j]==')'){
                if(l<kuo.size()){
                    kuo.erase(kuo.end()-1);
                }
                else if(r<que.size()){
                    int w=que[r];
                    s[w]='(';
                    r++;
                    
                }
                else{
                flag=1;
                break;
            
            }
            }
        }  
        for(int m=que.size()-1;m>=r&&!kuo.empty();m--){
            int w=que[m];
            int e=kuo.size() ;
            int q=kuo[e-1];
            if(q>w){
                flag=1;
                break;
            }
            else
            s[w]=')';
            kuo.erase(kuo.end()-1);
        }
        if(!kuo.empty())
        flag=1;
        if(flag==1)
        cout<<"No solution!";
else{
        for(int i=0;i<s.length();i++){
            if(s[i]!='*')
            cout<<s[i];
        }
    }
        cout<<endl;
    } 
    return 0;
}

1005

(没用组合数,之间是每次连一条边减去可能性)
刚开始的思路是减法,先算出总可能,之后每连一条边就减去失去的可能。当时不知道为什么一直没想出来可能性怎么减少。现在却有了思路。
用合并集的思路,把所有点看为一个独立的块。每当合并时,减少的情况只有合并的两个块与(把外面其他数看成一个整体)外面的块,各取一个数的情况。
证明一下:把要合并的块设为a,b;外面的整体看为c。
首先有一个块取两个的情况,a和b均不可能取2个(条件是两个数不能连通),c取两个与a和b中取一个的情况和a和b合并后取一个的情况是一样的。
一个块取三个的情况,只有c能取,又与a和b合并无关。
接下来各取一个有4种减小的情况:
1.a,b,c都取2。
2.a,b取2,c取1
3.a,c取2,b取1
4.b,c取2,a取1
之后是代码(需要快读和记忆化,不然会超时)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int fa[N],a[N],num1[N],num2[N];
int find(int x){
 if(fa[x]==x)return x;
 return fa[x]=find(fa[x]);
} 
inline ll read(){
 ll x=0,f=1;
 char c=getchar();
 while(c>'9'||c<'0'){
  if(c=='-') f=-1;
  c=getchar();
 }
 while(c>='0'&&c<='9'){
  x=x*10+c-'0';
  c=getchar();
 }
 return x*f;
}
int main(){
 int t;
  t=read();
   while(t--){
    ll cnt1=0,cnt2=0,n;
    n=read();
    for(int i=1;i<=n;i++){
     a[i]=read();
     if(a[i]==1)cnt1++,num1[i]=1,num2[i]=0;
     else cnt2++,num1[i]=0,num2[i]=1;
     fa[i]=i;
    }
 ll ans=(cnt2*(cnt2-1)*(cnt2-2)/6+cnt2*(cnt2-1)*cnt1/2);
 printf("%lld\n",ans%mod);
 for(int i=1;i<n;i++){
  int u,v;
  u=read(),v=read();
  int x=find(u),y=find(v);
  ans-=num2[x]*num2[y]*(cnt2-num2[x]-num2[y]);
  ans-=num2[x]*num2[y]*(cnt1-num1[x]-num1[y]);
  ans-=num1[x]*num2[y]*(cnt2-num2[x]-num2[y]);
  ans-=num2[x]*num1[y]*(cnt2-num2[x]-num2[y]);
  printf("%lld\n",ans%mod);
  fa[y]=x;
  num1[x]+=num1[y];
  num2[x]+=num2[y];
 }
 
   }
}

1007

当时没时间,只粗略的看了,求的是去掉k条边后的最大最短路径问题。结果是k的值较小,只要暴力搜索就行,每次搜索时都去掉最短路径上的一条边。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=1e9+7;
int t,pre[10][55],vis[55],n,k;
ll a[55][55],dis[55];
inline ll read(){
 ll x=0,f=1;
 char c=getchar();
 while(c>'9'||c<'0'){
  if(c=='-') f=-1;
  c=getchar();
 }
 while(c>='0'&&c<='9'){
  x=x*10+c-'0';
  c=getchar();
 }
 return x*f;
}
ll ans;
ll spfa(int x){
 for(int i=1;i<=n;i++)dis[i]=inf,pre[x][i]=-1,vis[i]=0;
 dis[1]=0;
 queue<int>q;
 q.push(1);
 while(!q.empty()){
  int u=q.front();
  q.pop();
  vis[u]=0;
  for(int i=1;i<=n;i++){
   if(u!=i&&dis[i]>dis[u]+a[u][i]){
    pre[x][i]=u;
    dis[i]=dis[u]+a[u][i];
    if(vis[i]==0){
     vis[i]=1;
     q.push(i);
    }
   }
  }
 }
 return dis[n];
} 
void dfs(int x){
 if(x==0){
  ans=max(ans,spfa(x));
  return;
 }
 spfa(x);
 int v=n;
 while(pre[x][v]!=-1){
  int u=pre[x][v];
  ll temp=a[u][v];
  a[u][v]=a[v][u]=inf;
  dfs(x-1);
  a[u][v]=a[v][u]=temp;
  v=u;
 }
}
int main(){
    t=read();
    while(t--){
     ans=0;
     n=read(),k=read();
     int len=n*(n-1)/2;
     for(int i=1;i<=len;i++){
      int u,v,w;
      u=read(),v=read(),w=read();
      a[u][v]=w,a[v][u]=w;
  }
  dfs(k);
  printf("%lld\n",ans);
 }
}

猜你喜欢

转载自blog.csdn.net/Nefeertari/article/details/107654538