130331周赛

A。主要考虑是否有0,分开判断即可。

int a[Max];
int main()
{
    int n , k;
    cin >> n >> k;
    int sign = 0 ;
    int haszero = 0;
    for (int i = 0 ; i < n ;i ++){
        scanf("%d",&a[i]);
        if(!a[i])haszero = 1;
        if(a[i] < 0)sign ++;
    }
    sort(a, a + n);
    if(k <= sign)
    {
        int ans = 0;
        for (int i = 0 ;i < n ;i ++)
        {
            if(k)
            {
                ans += abs(a[i]);
                k --;
            }
            else ans += a[i];
        }
        cout <<ans <<endl;
    }
    else
    {
        int ans = 0 ;
        for (int i = 0 ;i < n ;i ++)ans += abs(a[i]);
        if(haszero)
        cout <<ans <<endl;
        else
        {
            int min = inf;
            for (int i = 0 ;i < n ;i ++)if(min > abs(a[i])&& a[i] != 0)min = abs(a[i]);
            k -= sign ;
            if(k&1)
            ans -= min * 2;
            cout <<ans <<endl;
        }
    }
    return 0;
}
B。根据题意,肯定是选择容量最小的折扣,这样拿的免费物品最多。

int a[Max];
int vis[Max];
int main()
{
    int n , m ;
    cin >> n ;
    for (int i = 0 ; i < n ; i ++)cin >> vis[i] ;
    cin >> m ;
    for (int i = 0 ; i < m ; i ++)cin >>a[i] ;
    sort(a  , a + m );
    sort(vis , vis + n );
    int ans = 0 ;
    int free = 0 ;
    int nofree = vis[0];//容量最小的
    for (int i = m - 1 ;i >= 0 ;i --)
    {
        if(free > 0)
        {
            free -- ;
            nofree = vis[0];
            continue;
        }
        nofree -- ;
        if(!nofree)free = 2;
        ans += a[i];
    }
    cout << ans << endl;
}
C。dp,详见鸨神 http://blog.csdn.net/cugbbaoge/article/details/8753331

D。没啥陷阱

int a[100];
int main()
{
    int n , k ;
    cin >> n >> k;
    for (int i = 0 ;i < n ;i ++)scanf("%d",a + i);
    sort(a , a + n);
    if(k > n )
    cout << -1 <<endl;
    else if(k == n)
    cout <<0 <<" "<<0<<endl;
    else
    {
        cout <<a[n - k] <<" "<< 0 <<endl;
    }
}
E。给你n个节点,组成一个环,然后一共有2*n条路,这些路是相邻的两个点,也可以是中间隔着另外一点的两个点。

假设换是这样的a -> b- > c ->d -> e -> a。那么给你的路可能是a -> b,a->c, a -> e,a -> d。

一共是2*n条路。

然后求出任意一种环的顺序。

参考了CF上的代码。思路见注释。

vector<int>qq[Max*100];
int n ;
vector<int>ans;
bool vv[Max*100];

void dfs1()
{
    int l = ans.size();
    int x = ans[l - 1 ];
    int y = ans[l - 2 ];//取两个点。
    for (int i = 0 ; i < 4; i ++)
    {
        for (int j = 0 ; j < 4 ; j ++)
        {
            int px = qq[x][i];
            int py = qq[y][j];
            if(px == py && !vv[py])//这个判断非常巧妙,要是满足,则继续递归。如果满足这个条件,则x 与px直接相连,y与px直接相连,x 与 y隔着px相连。三者的关系就都满足了
            {
                vv[py] = 1 ;
                ans.pb(py);
                if(ans.size() < n )
                {
                    dfs1();
                }
                else
                {
                    // cout <<1;
                    for (int i = 0 ; i < ans.size(); i ++)
                        cout <<ans[i] + 1 <<" ";
                    exit(0);
                }
                vv[py] = 0 ;
                ans.pop_back();

            }
        }
    }
}
int main()
{
    cin >> n ;
    for (int i = 0 ; i < n * 2 ; i ++)
    {
        int  a , b ;
        cin >> a >> b;
        a-- , b --;
        qq[a].push_back(b);
        qq[b].push_back(a);
    }  	for (int i = 0 ; i < n ; i ++)
        if(qq[i].size() < 4)//任意点度数小于4,则输出-1
        {
            cout << -1 <<endl;
            return 0;
        }
    for (int i = 0 ; i < 4 ; i ++)//枚举和节点0相连的两点。
    {
        for (int j = 0 ; j < 4 ; j ++)
        {
            if(i != j)
            {
                int px = qq[0][i];
                int py = qq[0][j];
                vv[px] = 1 ;
                vv[py] = 1;
                ans.pb(px);
                ans.pb(py);
                dfs1();//从这两点出发开始找
                vv[px] = 0;
                vv[py] = 0;
                ans.pop_back();
                ans.pop_back();
            }
        }
    }
    cout << -1 <<endl;
    return 0;
}
F。题意:给你一幅图,求出长度大于k的环,并输出编号。

思路:从节点0开始搜,记录每个节点的深度,如果出现某个点已被访问(vis[n] != 0)那么证明这条链中有一个节点收尾相接了,即成环了。

那么他们的深度差就是环的长度。

看代码还是好理解的。

vector<int>q[Max*100];
int deep = 0 ;
int vv[Max*100];
int pre[Max*100];
int n , m , k;
bool flag = 0;
void dfs(int nn)
{
    for (int i = 0 ; i < q[nn].size(); i ++)
    {
        if(!vv[q[nn][i]])
        {
            vv[q[nn][i]] = vv[nn] + 1;
            pre[q[nn][i]] = nn;//记录前驱.
            dfs(q[nn][i]);
        }
        else if(vv[nn] - vv[q[nn][i]] + 1 > k)
        {
            int kk = nn;
            cout <<vv[nn] - vv[q[nn][i]] + 1 <<endl;
            for ( ; kk != q[nn][i]; kk = pre[kk])
                cout << kk + 1 <<" ";
            cout <<q[nn][i] + 1 <<endl;
            exit(0);
        }
        else
            continue;
    }
    return ;
}
int main()
{ 
    cin >> n >> m >> k;
    memset(vv,0,sizeof(vv));
    for (int i = 0 ; i < m ; i ++)
    {
        int a , b ;
        cin >> a >> b;
        a--,b--;
        q[a].push_back(b);
        q[b].push_back(a);
    }
    dfs(0);
    return 0;
}
G。模拟即可

int a[100005];
int main()
{
    int n ;
    cin >> n;
    for (int i = 0 ;i < n ;i ++)scanf("%d",a + i);
    int h = 0;
    ll ans = 0;
    for (int i = 0 ;i < n ;i ++)
    {
        ans += a[i] - h;//go to top
        ans ++ ;//eat
        if(i == n - 1)
        break;
        if(a[i + 1] <a[i] )
        ans += a[i] - a[i + 1];
        ans ++ ;//jump
        h = min(a[i],a[i + 1]);//updata the height
    }
    cout << ans <<endl;
}

H。也可以直接模拟做,记录 num值,最后排序输出。不过不知道精度够不够。

下面的就不需要那么麻烦了,我们根据左右的特点可以直接写出他的顺序。

如果往左,那么就是切掉右边,那么现在的值就是当前最大的。

如果往右,就是切掉左边,值就是当前最小的。

string a;
int b[10000005];
int main()
{
    cin >> a;
    int l = a.length();
    int lt = 0 ,rt = l - 1;
    for (int i = 0 ; i < l ; i ++)
    {
        if(a[i] == 'l')b[rt -- ] = i ;//cut the right , this is the RTth big num
        else b[lt ++ ] = i;//same
    }
    for (int i = 0 ; i < l ; i ++)cout <<b[i] + 1 <<endl;
}

I。这题也很巧妙。不需要判断两个数是否互质,直接将每个数的因子拿出来,进行dp.

int a[1000005];
int dp[1000005];
int b[1000005];
int main()
{
    int n ;
    cin >> n ;
    int ans = 0 ;
    int num = 1;
    for (int i = 0 ; i < n ; i ++ )
    {
        scanf("%d",a + i );
        dp[i] = 0;
    }
    for (int i = 0 ;i < n ;i ++)//a[i]是递增输入的
    {
        for (int j = 1 ;j * j <= a[i] ;j ++)
        {
            if(a[i] % j == 0)//找a[i]的因子
            {
                int x = j;
                int y = a[i] / j;
                if(x > 1)dp[i] = max(max(dp[i], b[x]),b[y]);//b[x]记录的是0 - i之间,有因子x且组成的最长序列。同理b[y]。
            }
        }
        for (int j = 1 ;j * j <= a[i] ;j ++)
        {
            if(a[i] % j == 0)//更新b[x],b[y]序列
            {
                int x= j ;
                int y = a[i] / j;
                if(x > 1)
                b[x] = max(b[x], dp[i] + 1);
                if(y != x)
                b[y] = max(b[y], dp[i] + 1);
            }
        }
    }
    for (int i = 0 ;i < n ;i ++)ans = max(ans, dp[i]);
    cout << ans + 1 <<endl;
    return 0;
}



 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值