【Codeforces】思维题做题记录

目录

1.Different Differences(贪心)

2. Divisible by Twenty-Five(模拟,构造)

3.Arrays Sum(思维)

4. Power Sequence(注意范围)

 5.Game of Ball Passing(思维,贪心)

6.MEX and Array(贡献法)

7.Doremy's Paint(思维)

8.Breaking the Wall(模拟,思维)

9.Remove Adjacent(贪心)

10.Anonymity Is Important(STL,模拟)


1.Different Differences(贪心)

链接:Problem - 1772C - Codeforces

题意:

解题思路:最大化相邻两个数之间的差值,从n开始减差值ax-ay=1,2,3.... (注意到最后如果不能让差值一直增加(因为要构造的数是1~n),如果不能增加了就固定为1)

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
	int t;cin>>t;
	while(t--)
	{
		int k,n;cin>>k>>n;
		int tmp=0,a[n];
		for(int i=1;i<=k;i++)
		{
			if(n-tmp>k-i)
			{
				n=n-tmp;
				a[i]=n;
				
			}
			else 
			{
			a[i]=a[i-1]-1;
			}
			tmp++;
		}
		for(int i=k;i>=1;i--)
		{
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}

return 0;
}

2. Divisible by Twenty-Five(模拟,构造)

链接:Problem - 1575D - Codeforces

题意:

解题思路:被25能整除的数末两位是25的倍数。00,25,50,75,根据最后两位数的情况构造

代码:

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
ll fast(ll x, ll n) {
    ll res = 1;
    while (n) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}
//25 50 75 00
ll solve(string s) {

    if (s[0] == '0') return 0;

    ll len = s.size();
    ll xia = 0, X = 0;

    for (ll i = 1; i < len - 2; ++i) 
	{
        if (s[i] == '_') xia++;
        if (s[i] == 'X') X++;
    }

    int tmp = 0;
    if (s[len - 2] == '_') 
	{
        if (s[len - 1] == '_') tmp = fast(10, xia) * 4;
        else if (s[len - 1] == 'X') {
            if (s[0] == 'X') return fast(10, xia) * 2 * (s[0] == '_' ? 9 : 1);
            else return fast(10, xia) * 4 * (s[0] == '_' ? 9 : 1);
        } else if (s[len - 1] == '0' || s[len - 1] == '5') tmp = fast(10, xia) * 2;
        else tmp = 0;
    } 
	else if (s[len - 2] == 'X') 
	{
        if (s[0] == 'X') {
            if (s[len - 1] == 'X') return 0;
            else if (s[len - 1] == '_') return fast(10, xia) * 3 * (s[0] == '_' ? 9 : 1);
            else if (s[len - 1] == '0') return fast(10, xia) * (s[0] == '_' ? 9 : 1);
            else if (s[len - 1] == '5') return fast(10, xia) * 2 * (s[0] == '_' ? 9 : 1);
            return 0;
        } else {
            if (s[len - 1] == '0' || s[len - 1] == '5') tmp = fast(10, xia) * 2;
            else if (s[len - 1] == '_') tmp = fast(10, xia) * 4;
            else if (s[len - 1] == 'X') tmp = fast(10, xia);
            else tmp = 0;
        }
    } 
	else if (s[len - 2] == '0' || s[len - 2] == '2' || s[len - 2] == '5' || s[len - 2] == '7')
	 {
        if (s[len - 2] == '0' || s[len - 2] == '5') 
		{
            if (s[len - 1] == '0') tmp = fast(10, xia);
            else if (s[len - 1] == 'X') 
			{
                if (s[0] == 'X') return 0;
                else 
				{
                    tmp = fast(10, xia);
                }
            }
            else if(s[len - 1]=='_') 
			{
                tmp = fast(10, xia);
            }
        } 
		else 
		{
            if (s[len - 1] == '5') tmp = fast(10, xia);
            else if (s[len - 1] == 'X') 
			{
                if (s[0] == 'X') return fast(10, xia) * (s[0] == '_' ? 9 : 1);
                else {
                    tmp = fast(10, xia);
                }
            }
        }
    } else tmp = 0;
    if (s[len - 1] != 'X' && s[len - 2] != 'X' && X != 0 && s[0] != 'X') tmp = tmp * 10;
    if (s[0] == '_' || s[0] == 'X') tmp = tmp * 9;

    return tmp;
}

int main() {
   ios::sync_with_stdio(false);
	cin.tie(0);
    string s;
    cin >> s;

    if (s.size() == 1) {
        if (s[0] == '0' || s[0] == '_' || s[0] == 'X') cout << 1;
        else cout << 0;
        return 0;
    }

    if (s.size() == 2) {
        if (s[0] == '0') cout << 0;
        else if (s[0] == '_') {
            if (s[1] == '_') cout << 3;
            else if (s[1] == 'X') cout << 3;
            else if (s[1] == '0') cout << 1;
            else if (s[1] == '5') cout << 2;
            else cout << 0;
        } else if (s[0] == 'X') {
            if (s[1] == '_') cout << 3;
            else if (s[1] == 'X') cout << 0;
            else if (s[1] == '0') cout << 1;
            else if (s[1] == '5') cout << 2;
            else cout << 0;
        } else if (s[0] == '2' || s[0] == '7') {
            if (s[1] == 'X' || s[1] == '_' || s[1] == '5') cout << 1;
            else cout << 0;
        } else if (s[0] == '5') {
            if (s[1] == 'X' || s[1] == '_' || s[1] == '0') cout << 1;
            else cout << 0;
        } else cout << 0;

        return 0;
    }

    ll res = solve(s);

    cout << res;

    return 0;
}

3.Arrays Sum(思维)

链接:Problem - 1408B - Codeforces

题意:

每一个b数组不同元素不超过k

解题思路:

因为他是单调递增数组,找到一共有多少不同元素sum,第一个b数组先包含前k个不同元素,其他的等于第k个元素如k=3【1,2,3,3,3...]

之后的b数组每个都可以解决k-1个元素,前面解决了的元素用0占位(所以只能解决k-1个)。

【既sum里面先减去k,剩下的sum里还包含多少(k-1)?】

特殊情况k==1,必须整个a数组元素相同否则输出-1

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		int n;cin>>n;
		double k;cin>>k;
		double a[110],sum[110]={0};
		for(int i=1;i<=n;i++)
		{ sum[i]=sum[i-1];
			cin>>a[i];
			if(i==1)sum[i]=1;
			else if(a[i]!=a[i-1])
			    sum[i]=sum[i-1]+1;  
		}

if(k==1)
{
	if(sum[n]!=1)cout<<-1<<endl;
	else cout<<1<<endl;
}
else
{

	if(k>=sum[n])cout<<1<<endl;//4 4 1,1,1,1
	else
	cout<<ceil((sum[n]-k)/(k-1))+1<<endl;//注意上取整 样例: 4 3 1,4,5,7
	
	 
}
}
return 0;
}

4. Power Sequence(注意范围)

链接:Problem - 1397B - Codeforces

题意:

思路:c直接从1开始枚举,算到最小成本后成本肯定会增大就可以break

注意当数达到1e18后就不能继续乘了

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+100;
ll a[N];
ll fast(ll x, ll n) {
    ll res = 1;
    while (n) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}
 ll n;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
cin>>n;
ll c=0;
for(int i=0;i<n;i++)
{
	cin>>a[i];
}
sort(a,a+n);
ll ans=1e18;
ll res=0;

for(ll i=1;;i++)
{ res=0;ll tt=1;
	for(int j=0;j<n;j++)
	{
		res+=abs(a[j]-tt);
		tt*=i;
		if(tt*i>=1e18)
		{
		break;//防止溢出
		}
	}
 if(res<ans)ans=res;
 else break;
 } 
cout<<ans;

return 0;
}

 5.Game of Ball Passing(思维,贪心)

链接:Problem - 1649B - Codeforces

题意:

思路:如果要传球最多次数的人小于剩下的人传球次数总和,那一定能用一个球传完,(每次都由最多的人传给其他人,其他人再传回来,直到把最多的人消耗完,又由下一个最多的重复以上步骤,一定能用一个球满足所有人的次数)

如果大于,传完剩下所有人后还有球在他手中,这时假设把他球传到空地,这就是球的个数。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+9;
int a[N];
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
int t;cin>>t;
while(t--)
{
	int n;
	cin>>n;
	ll sum=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];sum+=a[i];
		
	}
	sort(a+1,a+1+n);
	
if(a[n]==0)
{
cout<<0<<endl;
continue; 
}
else if(a[n]<=sum-a[n])
    cout<<1<<endl;
else 
{
	ll res=a[n]-(sum-a[n]);
	cout<<res<<endl;
}


}
return 0;
}

6.MEX and Array(贡献法)

链接:Problem - 1637B - Codeforces

题意:

思路:元素0 在每一个分段里面贡献值为2(1是长度c,另一个1是mex:除了0之外的最小是1)
         非零元素在每一个分段里面贡献为1 (1长度c)

找出每个元素在多少个分段(子数组)里:它前面的长度(包括它本身)*他后面的长度(包括它本身)

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
 int t;cin>>t;
 while(t--)
 {ll ans=0;
 	int n;cin>>n;
 	for(int i=1;i<=n;i++)
 	{
 		int a;cin>>a;
 		if(a==0)
 		{
 			ans+=2*(i)*(n+1-i);
		 }
		 else
		 {
		 	ans+=(i)*(n+1-i);
		 }
	 }
	 cout<<ans<<endl;
 }
return 0;
}

7.Doremy's Paint(思维)

链接:Problem - 1764A - Codeforces

题意:

思路:把r-l-c(l,r)展开理解,就是(r~l中的元素个数)-(r~l中的不同元素的个数),剩下的数就是r~l中每种相同元素的个数-1;

所以要最大化肯定要把含有相同元素的段全部包含进去,直接就是1~n

代码:

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=1e5+9;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
int t;cin>>t;
while(t--)
{
	int n;cin>>n;
	for(int i=1;i<=n;i++)
	{int x;
		cin>>x;
	}
	cout<<1<<" "<<n<<endl;
}
return 0;
}

8.Breaking the Wall(模拟,思维)

链接:Problem - 1674E - Codeforces

题意:

思路:只有3种情况:

1.两个相邻的,2.三个中两边的(先打中间),3.最小的两个墙距离大于3(两个分开打) 

3:分开打,每一个次数对答案的贡献都是2,墙小于2后对答案贡献1

2:先打中间的(对答案贡献2)直到其中一个=0,然后打另一个(对答案贡献2或1)

1:如果相邻两个中max>=2*min那直接打max向上取整

      如果max<2*min:打(max+min)时每一次对答案贡献3(也要上取整)

代码:

#include<bits/stdc++.h>
typedef long long ll;
const int N=2e5+9;
int a[N],b[N];
using namespace std;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
	int n;cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[i]=a[i];
	 } 
	 
sort(b+1,b+1+n);
int r1=b[1],r2=b[2];
int ans1=0,ans2=1e9,ans3=1e9;
ans1=r1/2+r1%2+r2/2+r2%2;

for(int i=1;i<n;i++)//相邻的
{
	
int x=a[i],y=a[i+1],tmp=0;
int mi=min(x,y);
int ma=max(x,y);

if(ma>=mi*2) tmp=(ma+1)/2;
else tmp=(ma+mi+2)/3;
if(tmp<ans2)ans2=tmp; 
}

for(int i=1;i<n-1;i++)
{
	int x=min(a[i],a[i+2]);
	int y=max(a[i],a[i+2]);
//	cout<<x<<endl<<y;
	int tmp=x+(y-x)/2+(y-x)%2;
	if(tmp<ans3)ans3=tmp;
	
}
//cout<<"ans1:"<<ans1<<"ans2:"<<ans2<<" "<<ans3<<endl;
int res=min(ans1,min(ans2,ans3));
cout<<res;
return 0;
}

9.Remove Adjacent(贪心)

链接:Problem - 1321C - Codeforces

题意:

也就是只要左,右有它前一个字母就可以把它自己删掉 

思路:大的字母先删肯定是最优的,因为它不可能让别人被删掉,只能自己被删

代码:

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

int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
	int s;cin>>s;
	string a;cin>>a;
   int ans=0;
   for(char i='z';i>='a';i--)//优先去掉大的更好,因为大的不能作为删别人的依据
   {
   	for(int j=0;j<a.size();j++) 
   	{
   		if(a[j]==i&&(j>0&&a[j-1]==i-1||j<a.size()-1&&a[j+1]==i-1))
   		{
   			a.erase(j,1);j=-1;//每一次都从新找,直到这个大的没有了,就不会进入这个if ,就会找下一个大的字母 
			   ans++;
		   }  
	}
   }
 
cout<<ans;

return 0;
}

10.Anonymity Is Important(STL,模拟)

链接:Problem - 1641C - Codeforces

题意:

思路: 可以用set代表不确定的人,初始化都是不确定则将所有人插入st.将不是病人的从set里删除。对于至少有一个病人的区间尽可能缩小到只有一个人的区间,用map[l]=r存,将会包含别的区间的大区间不插入,或删掉,(因为st存的是不确定的人所以大区间中表示至少有一人也是不确定,则可以用小区间代替)。

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;	
map<int,int>mp;
set<int>st;
int main()
{
ios::sync_with_stdio(false);
	cin.tie(0);
	int n,q;cin>>n>>q;
	for(int i=0;i<=n+1;i++)st.insert(i);
	while(q--)
	{
	
		
		int t;cin>>t;
		if(t)
		{
			int j;cin>>j;
			if(!st.count(j))
			cout<<"NO"<<endl;
			else
			{
				int l=*prev(st.find(j));
				int r=*next(st.find(j));
				auto it=mp.upper_bound(l);
				if(it!=mp.end()&&it->first<=j&&it->second<r)cout<<"YES"<<endl;
				else cout<<"N/A"<<endl;
			}
		}
		else
		{
			int l,r,x;
			cin>>l>>r>>x;
			if(x==0)
			{
				while(1)
				{
					auto it=st.lower_bound(l);
					if(*it>r)break;
					st.erase(it);
				}
			}
			else
			{
				auto it=mp.lower_bound(l);
				if(it!=mp.end()&&it->second<=r)continue;
				mp[l]=r;
				it=mp.find(l);//找前面有没有包含他 
				while(it!=mp.begin()&&r<=prev(it)->second)mp.erase(prev(it));
			}
		}
	}

return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值