2021-2-24队内个人赛

2021-2-24对内个人赛

A题 CodeForces - 1303A

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

char s[105];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s+1);
        int ans=0,pre=0,len=strlen(s+1);
        for(int i=1;i<=len;i++)
        {
            if(s[i]=='0')
                continue;
            if(pre)
                ans+=i-pre-1;
            pre=i;
        }
        printf("%d\n",ans);
    }
    return 0;
}


B CodeForces - 1300A

首先我们考虑数列中出现的0,只要有0存在,那么数列中所有数字的积必定为0,所以我们先把数列中的所有0变成1.在进行这样的操作后,我们再检查一下这个时候数列中所有数字的和是否为0,如果为0 的话再加一次1就可以了(和为0的话,必定又有负数又有整数,随便选一个正数+1就能避免0的再次出现)

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
	IOS;
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		int sum=0,res=0;
		while(n--){
			int x;
			cin>>x;
			if(x==0){
				x++;
				res++;
			}				
			sum+=x;			
		}
		if(sum==0)
			res++;
		cout<<res<<endl;
	}
	return 0;
}

C CodeForces - 40A

看各位的代码有点麻烦,看看我这优雅的代码吧

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
int x,y,l,r;
int main(){
	scanf("%d%d",&x,&y);
	l=x*x+y*y;
	for(r=1;r*r<l;r++);
	puts(r*r==l||(r&1)^(x*y<0)?"black":"white");
	return 0;
}

D CodeForces - 46B

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
 
string M[5]= {"S","M","L","XL","XXL"};
 
int main()
{
	IOS;
	int k,n[5];
	for(int i=0;i<5;i++)
		cin>>n[i];
	cin>>k;
	for(int i=0;i<k;i++)
	{
		string s;
		cin>>s;
		int j;
		for(j=0;s!=M[j];j++);
		int b=-1000;
		for(int k=0;k<5;k++)
		{
			if(!n[k])
				continue;
			if(abs(k-j)<=abs(b-j))
				b=k;
		}
		cout <<M[b]<<endl;
		n[b]--;
	}
	return 0;
}

E CodeForces - 48B

一眼看会有点不知所措,再仔细一看其实就是求一个矩阵前缀和,然后行列各扫一遍,求差的最小值嘛。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int s[55][55],maxn=9999999;
int main()
{
	IOS;
	int n,m,r,c,i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
		{
			cin>>s[i][j];
			s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+s[i][j];
		}
	cin>>r>>c;
	for(i=r;i<=n;i++)
		for(j=c;j<=m;j++)
			maxn=min(maxn,s[i][j]-s[i-r][j]-s[i][j-c]+s[i-r][j-c]);
	swap(r,c);
	for(i=r;i<=n;i++)
		for(j=c;j<=m;j++)
			maxn=min(maxn,s[i][j]-s[i-r][j]-s[i][j-c]+s[i-r][j-c]);
	cout<<maxn;
}

F CodeForces - 1293B

简单结论题
首先我们要知道,总共是n个人,不管我们怎么选择方案,所有的分数(未约分过)的分子部分累加起来都是n。在分子总数固定的情况下,我们需要让每个分子对应的分母尽可能小,这样才能使得值更大。
假设我们在n个人中去掉两个人,有两种方案,一种是2/n也就是1/n+1/n,另一种是1/n+1/(n-1),明显后面的那个更大。可以由此推出一个结论,最优方案就是每次只让一个人出局。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
typedef long long ll;
int main()
{
    IOS;
	ll n;
    cin>>n;
    double ans=0;
    for(ll i=1;i<=n;i++)
    {
        ans+=(double)1/i;
    }
    cout<<ans<<endl;

}

G CodeForces - 1304B

这道题我也卡了很久疯狂wa,细节坑我。
由于所有的字符串长度都是相等的,因此最后的字符串必然可以切割成长度为m的部分,并且对称的部分只能是两个原本的字符串,或者是最为最终回文串的中间部分的那个字符串,它需要满足自己就是个回文串。
直接暴力匹配是否有对称的字符串就行了,注意中间还可以放一个自身就是回文串的字符串。`

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f //1061109567
#define llINF 9223372036854775807
#define ll long long
const ll maxn=1e2+7;
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

bool flag[maxn];
string s[maxn];

int main()
{
    IOS;
    ll n,m;
    cin>>n>>m;
    for(ll i=1;i<=n;i++) cin>>s[i];
    string ans,mid,right;//ans暂存左侧部分,mid保存中间可能存在的对称部分,right保存右侧部分,也就是ans的镜像
    for(ll i=1;i<=n;i++)
    {
        bool F=0;   //F记录是否存在字符串与当前字符串镜像
        for(ll j=i+1;j<=n;j++)
        {
            if(!flag[j])    //如果该字符串仍然未被使用
            {
                bool f=1;   //记录s[i]和s[j]是否为对称的字符串
                for(ll k=0;k<m;k++)
                    if(s[i][k]!=s[j][m-k-1]) f=0;
                if(f)   //如果满足
                {
                    flag[j]=1;  //使用字符串j
                    right=s[j]+right;   //将字符串j加到right部分去
                    F=1;        //记录找到s[i]的对称字符串,跳出循环
                    break;
                }
            }
        }
        if(F)   ans+=s[i];  //如果找到了对称的字符串,那就把s[i]加到左侧的ans去
        else    //如果没找到的话那就检测s[i]自身是不是一个回文串,如果是就放到mid部分去。
        {
            F=1;
            for(ll j=0;j<m;j++)
                if(s[i][j]!=s[i][m-j-1]) F=0;
            if(F) mid=s[i];
        }
    }
    ans+=mid+right; //拼接ans+mid+right
    cout<<ans.size()<<endl;
    cout<<ans<<endl;
}


H CodeForces 75C

给出 a , b 问你在区间 [ l . r ] 中的最大公因子是多少,区间内的最大大公因子肯定是 g c d ( a , b ) 的因子,所以先把最大公因子的所有因子都预处理出来,在区间内二分查找就行了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll c[100010];
ll gcd(ll a,ll b)
{
    return b ? gcd(b,a%b) : a;
}

int main()
{
    ll a,b,n,d,k=0;
    scanf("%lld%lld%lld",&a,&b,&n);
    d=gcd(a,b);
    for(int i=1;i*i<=d;i++)
    {
        if(d%i==0)
        {
            c[k++]=i;
            if(i*i!=d)c[k++]=d/i;
        }
    }
    sort(c,c+k);

    while(n--)
    {
        ll l,h;
         scanf("%lld%lld",&l,&h);
         if(l>d)//区间始终比最大公约数大
         {
             printf("-1\n");
             continue;
         }
         ll ans;
         ans=upper_bound(c,c+k,h)-c-1;
         if(ans==-1||c[ans]<l)//没找到或c[ans]<l并且c[ans+1]>h
        {
             printf("-1\n");
             continue;
         }
         printf("%lld\n",c[ans]);

    }
}


I CodeForces - 1293C

本题也还是个思维题,题面迷惑性比较大
对于每一个格子,我们考虑的是它的通或者不通,与哪些格子组合起来会对结果产生影响。
如果要走过的地图上有一块陷阱(x, y), 并且陷阱所在的另一行上的(x, y+1)或(x, y)或(x, y-1)三块中的任何一块内也有陷阱, 则一定是无法达到终点的. 所以不妨每当出现一种无法通过的情况, 我们就记录一次, 如果没有不可通过的情况则就可以通过.

#include<bits/stdc++.h>
using namespace std;

const int maxx=1e5+100;
int vis[3][maxx];
int n,q;

int main()
{
	scanf("%d%d",&n,&q);
	int x,y;
	int ans=0;
	for(int i=1;i<=q;i++) 
	{
		scanf("%d%d",&x,&y);
		if(vis[x][y]==0)
		{
			vis[x][y]=1;
			if(vis[3-x][y]) ans++;
			if(vis[3-x][y+1]&&y+1<=n) ans++;
			if(vis[3-x][y-1]&&y-1>=1) ans++;
		}
		else 
		{
			vis[x][y]=0;
			if(vis[3-x][y]) ans--;
			if(vis[3-x][y+1]&&y+1<=n) ans--;
			if(vis[3-x][y-1]&&y-1>=1) ans--;
		}
		if(!ans) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
}

J CodeForces - 1295C

贪心,dp优化字符串匹配
暴力匹配是超时的,用dp数组来记录每个位置后每个字符对应位置下标,O(1)查询下一个匹配字符的位置就好了。

#include<bits/stdc++.h>
#define INF 0x7f7f7f7f //2139062143
#define INF1 0x3f3f3f3f //1061109567
#define INF2 2147483647
#define llINF 9223372036854775807
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

char a[100010],b[100010];
int dp[100010][26],Flag[26];//dp[i][j]记录在第i个下标开始往后找,第一个字符('a'+j)所在的位置的下一个位置(也就是接下去开始匹配的第一个位置),如果等于INF2则代表已经不存在字符('a'+j)
//Flag[i]记录字符('a'+j)是否在字符串a中出现,用于检测能否构建字符串b,如果字符串b需要的某个字符在字符串a中不存在,那么必然无法构建。

void clr()
{
    for(int i=0;i<100010;i++)
        for(int j=0;j<26;j++)
            dp[i][j]=INF2;
    for(int i=0;i<26;i++)
        Flag[i]=0;
}

int main()
{
    IOS;
    int T;
    cin>>T;
    cin.get();
    while(T--)
    {
        cin.getline(a,100010);
        cin.getline(b,100010);
        clr();
        int lens=strlen(a),lent=strlen(b);
        for(int i=lens-1;i>=0;i--)  //从后往前更新dp数组
        {
            int x=a[i]-'a';
            Flag[x]=1;
            for(int j=0;j<26;j++)   //直接复制i+1位置以后的26个字母出现的第一个下标位置
                dp[i][j]=dp[i+1][j];
            dp[i][x]=i+1;   //更新当前位置的字母,位置置为当前位置的后一个//我们匹配i位置后的字符('a'+x)后,待匹配的第一个位置就是i+1
        }
        int flag=1;
        for(int i=0;i<lent;i++)
        {
            if(Flag[b[i]-'a']==0)
            {
                flag=0;
                break;
            }
        }
        if(flag)
        {
            int now=0,ans=1;    //now记录我们当前字符串a中匹配到了哪个位置,至少匹配一次,ans初始化1
            for(int i=0;i<lent;i++)
            {
                now=dp[now][b[i]-'a'];
                if(now==INF2)   //匹配到了末尾,ans次数+1,从字符串a的0位置开始找并更新now
                {
                    ans++;
                    now=dp[0][b[i]-'a'];
                }
            }
            cout<<ans<<endl;
        }
        else cout<<-1<<endl;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值