CodeForces 1082 训练

A. Vasya and Bookt

题目链接:http://codeforces.com/problemset/problem/1082/A

题目大意:现在给出一本书这本书共有N页,现在让你从第X页翻到第Y页,且每次都只能翻K页,最多翻到第N页最少翻到第1页,也就是到了边界是不能越界的,只能翻到边界页数

思路:是否能直接从x页翻到y页,是否能从第一页翻到y页,是否能从最后一页翻到y页;只要有满足的即可

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;

int main()
{
	int t,n,d,x,y,s,s1,s2,num,num1,num2,flag;
	cin>>t;
	while(t--)
	{
		flag=0;
		cin>>n>>x>>y>>d;
		s=abs(x-y);
		if(s%d==0)
		{
			cout<<s/d<<endl;   //从第X页直接翻到第Y页,就是最短的
			continue;
		}
		if((n-x)%d==0)
			s1=(n-x)/d;
		else
			s1=(n-x)/d+1;
		if((x-1)%d==0)
			s2=(x-1)/d;
		else
			s2=(x-1)/d+1;

		if((n-y)%d==0)
			num1=(n-y)/d+s1;
		else
			num1=inf;
		if((y-1)%d==0)
			num2=(y-1)/d+s2;
		else
			num2=inf;
		num=min(num1,num2);
		if(num==inf)
			cout<<"-1"<<endl;
		else
		cout<<num<<endl;
	}
	return 0;
}

 

B.Vova and Trophies

题目链接:http://codeforces.com/problemset/problem/1082/B

 

题目大意:给出一个长度为N 的字符串,其中只包含G和S两个字符,现在你有一次交换的机会(并不一定是相邻的交换),让其中的G的连续子串的长度最长,并输出这个子串的长度

思路:记录中间 ‘S’ 前面的 ‘G’的长度 和 后面 'G' 的长度,取最大值 maxlen。最后答案和 总的‘G’数量 snt 进行一下比较,如果大了说明多加的,输出 snt,否则输出 maxlen

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
string a;
int main()
{
    int n,ans=0,temps=0,sumg=0,tempg=0;
    cin>>n;
    cin>>a;
    for(int i=0;i<n;i++)
    {
        if(a[i]=='G')
        {
            sumg++;
            tempg++;
        }
        else
        {
            temps=tempg;
            tempg=0;
        }
        ans=max(ans,tempg+temps+1);
    }
    ans=min(ans,sumg);
    cout<<ans<<endl;
    return 0;
}

C. Multi-Subject Competition

题目链接:http://codeforces.com/problemset/problem/1082/C

题目大意:比如现在有N个人,有M个比赛,且对于每一个人,你都知道他对某个比赛ID的能力VAL,求出每场比赛参加人数相同时候的最大VAL和

思路:

从网上看到了这个图,贼鸡儿受启发,直接明白题意了。。。。

其余的,就是模拟这个过程。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#define maxn 100010
using namespace std;

int n,m;
int sum[100010];
vector<int >G[100010];

int cmp(int a,int b)
{
    if(a>b)
        return 1;
    else
        return 0;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            int id,val;
            cin>>id>>val;
            G[id].push_back(val);
        }

        for(int i=1;i<=m;i++)
        {
            sort(G[i].begin(),G[i].end(),cmp);
        }

        for(int i=1;i<=m;i++)
            for(int j=1;j<G[i].size();j++)
                G[i][j]+=G[i][j-1];

        int ans=0;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<G[i].size();j++)
            {
                if(G[i][j]>0)
                    sum[j]+=G[i][j];
                ans=max(ans,sum[j]);
            }
            G[i].clear();
        }
        printf("%d\n",ans);
    }
    return 0;
}

E. Increasing Frequency

题目链接:http://codeforces.com/problemset/problem/1082/E

题目大意:给你n(n<=1e5)个数和一个数c,你只能把一段连续区间里的数都加上k(k由你自己定),使得整个序列含c尽可能的多。

思路:

思路参考自:https://blog.csdn.net/LSD20164388/article/details/84697742 谢谢大佬!!!

dp[i]表示从前面某个位置pos开始,到现在的位置i,把pos~i之间的(出现次数最多的)数变成c,前pos-1个不变的最大的含c的数量。

pre[x]=j表示对于某个数a[i]==x,它上一次出现的位置是j。即a[j]=a[i]=x。

qian[i]表示从第一个位置到当前位置i时c出现的次数。

hou[i]表示从最后一个位置到当前位置i时c出现的次数。

那么状态转移方程就出来了:

dp[i]=max(qian[i-1]+1,dp[pre[a[i]]]+1);

pre[i]=i;

ans=max(ans,dp[i]+hou[i+1]);

这样就可以保证某个位置pos开始,dp[pos+1]~dp[i]这一段出现次数最多的数都变成了c的最大的c的数量。

代码:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
using namespace std;
const int maxn=500000+10;
int n,k,m;
int cnt,tmp,flag,ans;
int dp[maxn];
int a[maxn],c[maxn],pre[maxn],qian[maxn],hou[maxn];
int main()
{
 
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        qian[i]=qian[i-1]+(a[i]==k);
    }
    for(int i=n;i>=1;i--)
    {
        hou[i]=hou[i+1]+(a[i]==k);
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=max(qian[i-1]+1,dp[pre[a[i]]]+1);
        pre[a[i]]=i;
        ans=max(ans,dp[i]+hou[i+1]);
    }
    printf("%d\n",ans);
    return 0;
}

 H.POJ 3617

http://poj.org/problem?id=3617

参考自:https://blog.csdn.net/sevenmit/article/details/13304489  谢谢大神!!!

题目: 给定长度为N的字符串S, 要构造一个长度为N的字符串T. 反复进行如下任意操作.

从S的头部删除一个字符, 放入T的尾部;

从S的尾部删除一个字符, 放入T的尾部;

目标是要构造字典序尽可能小的字符串T.

思路:这题主要是用贪心,目标主要是从已知的字符串构造出字典序尽可能小的字符串从字典序性质来看,无论字符串末尾有多大,只要保证前面部分较小就可以咯!*假设原来字符串为S,目标字符串为T,那么,不断取出S的开头和末尾较小的一个字符放到T的末尾。上面的没有针对开头与结尾相同,如果,遇到这样动情况,应该比较下一个字符的大小。如果,下一个字符也相同,那么可以得到下面的算法:

按照字典序比较S和将S反转后的字符串S’*如果,S较小,那么取出S开头字符,追加到T的末尾
如果,S'较小,那么取出S结尾字符,追加到T的末尾
如果,相同则取出那一个都可以。

代码:

 


#include <iostream>
#include <string>
 
using namespace std;
 
int n;
char s[2010];
 
void solve()
{
    int start = 0, end = n - 1,count = 0;
    while(start <= end)   // 将从左起和从右起的字符串比较
    {
        bool flag = false;
        for(int i = 0; i <= end - start; i++)  // 字符串的开头与结尾相同,则继续比较下一个
        {
            if(s[start+i] < s[end-i])  
            {
                flag = true;
                count++;
                break;
            }
            else if(s[start+i] > s[end-i])
            {
                flag = false;
                count++;
                break;
            }
        }
        if(flag) cout<<s[start++];
        else cout<<s[end--];
        if(count % 80 == 0)
        cout<<endl;
    }
    cout<<endl;
}
int main(void)
{
    cin>>n;
    for(int i = 0; i < n; i++)
    cin>>s[i];
    solve();
    return 0;
}

I.Kill the monster(HDU 2616)

http://acm.hdu.edu.cn/showproblem.php?pid=2616

有n组数据,和怪兽血量m,每组数据有两个数,第一个为普通伤害值,第二个为怪兽血量少于该值时将造成双倍伤害,,求最少攻击次数,不死则输出-1.
DFS:比较明显的dfs,时间复杂度为O(n!),数据比较小而且不强,可以直接DFS 过了 代码

代码:


#include<stdio.h>
#include<string.h>
int n,m;
int a[10][2];
int vis[10];
int cnt;
void dfs(int c,int s)
{
    if(s<=0 && c<cnt){
        cnt=c;
        return;
    }
    if(c>=cnt) return;
    for(int i=0;i<n;i++)
        if(!vis[i]){
            vis[i]=1;
            int temp=(s<=a[i][1]?s-2*a[i][0]:s-a[i][0]);
            dfs(c+1,temp);
            vis[i]=0;
        }
        
}
int main(void)
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i][0],&a[i][1]);
        memset(vis,0,sizeof(vis));
        cnt=10;
        dfs(0,m);
        if(cnt==10) puts("-1");
        else printf("%d\n",cnt);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值