Codeforces Round #369 (Div. 2) A~D

前言:这场又蹦了。。。还是老老实实补题吧。
A:水题就不说了

#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
using namespace std;
string s[1010];
int main(){
    int n;
    while(cin>>n){
        int ans=0;
        rep(i,0,n){
           cin>>s[i];
           if(!ans){
            if(s[i][0]=='O'&&s[i][1]=='O'){
              s[i][0]='+';s[i][1]='+';
              ans=1;
            }
            else if(s[i][3]=='O'&&s[i][4]=='O'){
              s[i][3]='+';s[i][4]='+';
              ans=1;
            }
           }
        }
        if(!ans) cout<<"NO"<<endl;
        else{
            cout<<"YES"<<endl;
            rep(i,0,n) cout<<s[i]<<endl;
        }
    }
}

B:
题意:n*n矩阵 里,有一个位置是0,待你填入一个大于0的数,使得矩阵每行,每列,两对角线之和相等,输出可能存在的这个数,不存在输出-1.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[800][800];
int n;
bool check(int x,int y,ll v){
   a[x][y]=v;
   ll ans=0,sum=0;
   for(int i=1;i<=n;i++) ans+=a[1][i];
   for(int i=1;i<=n;i++){
       sum=0;
       for(int j=1;j<=n;j++) sum+=a[i][j];
       if(sum!=ans) return false;
   }
   for(int i=1;i<=n;i++){
      sum=0;
      for(int j=1;j<=n;j++) sum+=a[j][i];
      if(sum!=ans) return false;
   }
   sum=0;
   for(int i=1;i<=n;i++) sum+=a[i][i];
   if(sum!=ans) return false;
   sum=0;
   for(int i=1;i<=n;i++) sum+=a[i][n+1-i];
   if(sum!=ans) return false;
   return true;
}

int main(){
    while(~scanf("%d",&n)){
        int x,y;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cin>>a[i][j];
                if(a[i][j]==0) {x=i;y=j;}
            }
        }
        if(n==1){
            cout<<10<<endl;
            continue;
        }
        ll sum=0,ans=0;
        int p=1;
        while(x==p) p++;
        for(int i=1;i<=n;i++){
            sum+=a[x][i];
            ans+=a[p][i];
        }
        if(check(x,y,ans-sum)&&ans-sum>0) cout<<ans-sum<<endl;
        else cout<<-1<<endl;
    }
}

C:
题意:有n个数的序列,多少个不相同的连续序列的个数是他的美丽度。比如 :1 2 2 1 美丽度是3 ,{1} {2,2} {1}三个不相同的连续序列。
同时每个位置可能预先被选定一个颜色,0表示没有选定。同时给出每个位置用哪个颜色(数字)代价是不同的,问整个串美丽度为k的最消耗费是?
思路:典型区间dp问题。设dp[i][j][k]表示:选到第i个数,美丽度为j的情况下选择k的颜色的最小耗费。
我的做法O(n^4) n<=100
那么详细的转移方程见代码 :

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x7fffffffffff;
ll dp[110][110][110],cost[110][110],c[110];
int main(){
   int N,M,K;
   while(~scanf("%d%d%d",&N,&M,&K)){
      for(int i=1;i<=N;i++) scanf("%I64d",&c[i]);
      for(int i=1;i<=N;i++){
        for(int j=1;j<=M;j++){
           scanf("%I64d",&cost[i][j]);
        }
      }
      for(int i=0;i<=N;i++){
        for(int j=0;j<=K;j++){
           for(int k=0;k<=M;k++){
              dp[i][j][k]=inf;
           }
        }
      }
      if(c[1]==0){
        for(int i=1;i<=M;i++) dp[1][1][i]=cost[1][i];
      }
      else{
        dp[1][1][c[1]]=0;
      }
      for(int i=2;i<=N;i++){
         for(int j=1;j<=K;j++){
             if(c[i]==0){
                for(int k=1;k<=M;k++){
                    for(int l=1;l<=M;l++){
                        if(k!=l) dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-1][l]+cost[i][k]);
                        else  dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]+cost[i][k]);
                    }
                }
             }
             else{
                for(int k=1;k<=M;k++){
                    if(k!=c[i]) dp[i][j][c[i]]=min(dp[i][j][c[i]],dp[i-1][j-1][k]);
                    else dp[i][j][c[i]]=min(dp[i][j][c[i]],dp[i-1][j][c[i]]);
                }
             }
         }
      }
      ll ans=inf;
      for(int i=1;i<=M;i++) ans=min(ans,dp[N][K][i]);
      if(ans>=inf) printf("-1\n");
      else printf("%I64d\n",ans);
   }
}

D:
题意:
给出一个n个节点n条边的有向图,可以把一条边反向,现在问有多少种方式可以使这个图没有自循环的环;
思路:可以发现一共n个边,对于一个环来说,随便反转哪些边就可以,不过有两种不行就是都不反转和都反转,假设这个环有s条边,那么就有2^s-2种方式,其他不在环里的边sum可以反转可以不反转;
所以答案:(2^s-2)*2^sum
具体找每个环内有多少边,和总工有多少边在 环里,一个dfs就好。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2*100000+10;
const ll mod=1e9+7;
int a[N],vis[N],dep[N],sum=0;
ll ans;
ll pow_mod(ll a,ll n){
    ll as=1;
    ll tmp=a%mod;
    while(n){
        if(n&1) as=(as*tmp)%mod;
        tmp=tmp*tmp%mod;
        n>>=1;
    }
    return as;
}

int dfs(int cur,int deep,int fa){
    vis[cur]=fa;
    dep[cur]=deep;
    if(!vis[a[cur]]) dfs(a[cur],deep+1,fa);
    else if(vis[a[cur]]==fa){
        ans=ans*(pow_mod(2,dep[cur]-dep[a[cur]]+1)-2+mod)%mod;
        sum+=dep[cur]-dep[a[cur]]+1;
    }
}

int main(){
    int n;
    while(~scanf("%d",&n)){
       ans=1;sum=0;
       memset(vis,0,sizeof(vis));
       for(int i=1;i<=n;i++) scanf("%d",&a[i]);
       for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0,i);
       ans=ans*pow_mod(2,n-sum)%mod;
       printf("%I64d\n",ans);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值