ACM训练补题

题目-最少01翻转次数 (51nod.com)(思维 前缀和 后缀和 枚举)

参考文献:(27条消息) 51nod 2517 最少01翻转次数_林子盛吧(✪ω✪)的博客-CSDN博客

思路:

序列不降的情况有三种:假设元素有6个

000000 000111 111111

也就是选定一个位置把此位置之前的1翻转为0,之后的1翻转为0以保证序列不降。因此我们枚举整个区间,对于每个ai,枚举前面有多少个1,后面有多少个0,因此我们利用前缀和和后缀和来统计每个位置ai的所有情况

这样对于每个位置情况预处理的序列都是合法的,所以我们只需要统计

每个位置的前缀和后缀和的最小值就行了

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10;
int head[N],tail[N];
char a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    
    //预处理前缀和
    for(int i=0;i<n;i++)
    {
        head[i+1]=head[i];
        if(a[i]=='1') head[i+1]++;
    }
    
   //预处理后缀和
    for(int i=n-1;i>=0;i--)
    {
        tail[i-1]=tail[i];
        if(a[i]=='0') tail[i-1]++;
    }
    
    int res=0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        res=min(res,tail[i]+head[i]);
    }
    
    cout<<res<<endl;
    
}

Han Solo and Lazer Gun - CodeForces 514B - Virtual Judge (csgrandeur.cn)

题意:有一把枪,可以射击一条直线上的所有敌人(斜线也可以),现在给你枪的位置和n个敌人的坐标,求至少要射击多少次

错误:因为选择的语言不同g++14竟然错了,下次选最新版本hh

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n;
double x,y;
int main()
{
   cin>>n>>x>>y;
   int flag=0;set<double> st;
   for(int i=0;i<n;i++)
   {
   	  double x1,y1;
	  cin>>x1>>y1;
	  if(x1==x) flag=1;
	  else 
	  {
	  	double k=(y-y1)/(x-x1);
	    st.insert(k);
	  } 
   }
   cout<<st.size()+flag<<endl;
   return 0;
}

程序设计:迷宫 - 计蒜客 43113 - Virtual Judge (csgrandeur.cn)

思路:bfs搜索,迷宫经典例题,优先考虑起点和是否进入传送门

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+10,M=1;
typedef pair<int,int> PII;
int n,m,endx,endy;
map<PII,PII> mp;
map<PII,bool> mp1;
char a[N][N];
int d[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void bfs()
{
	queue<PII> q;
	memset(d,-1,sizeof(d));
	d[1][1]=0;
	q.push(make_pair(1,1));
	while(q.size())
	{
		PII t=q.front();
		q.pop();
		if(a[t.first][t.second]=='*'||d[t.first][t.second]==-1) continue;
		else if(mp1[make_pair(t.first,t.second)]==true)
		{
			d[mp[t].first][mp[t].second]=d[t.first][t.second];
			//cout<<mp[t].first<<mp[t].second;
			q.push(mp[t]);
		}
		else
		{
		for(int i=0;i<4;i++)
		{
			int x=t.first+dx[i],y=t.second+dy[i];
			if(x>=1&&x<=n&&y>=1&&y<=m&&a[x][y]=='.'&&d[x][y]==-1)
			{
				d[x][y]=d[t.first][t.second]+1;
				q.push(make_pair(x,y));
			}
	    }
    }
}
}
int main()
{
   cin>>n>>m;
   for(int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			cin>>a[i][j];
		}
	}
   int q;
   cin>>q;
   while(q--)
   {
   	  int x1,y1,x2,y2;
   	  cin>>x1>>y1>>x2>>y2;
   	  //cout<<x1<<y1<<x2<<y2<<endl;
   	  mp1[make_pair(x1,y1)]=true;
   	  mp[make_pair(x1,y1)]=make_pair(x2,y2);
   	  //cout<<mp[make_pair(x1,y1)].first<<" "<<mp[make_pair(x1,y1)].second<<"qaq"<<endl;;
   }
   cin>>endx>>endy;
   bfs();
   if(d[endx][endy]==-1)
   {
   	   cout<<"No solution"<<endl;
   	   return 0;
   }
   cout<<d[endx][endy]<<endl;
   return 0;
}

 Fadi and LCM - CodeForces 1285C - Virtual Judge

思路:第一次写的时候tle了,原因是双重循环o(n*n),数据太大了,后来发现因为要求一个数对应数对的最大公约数是这个数且这个数对max尽可能要小,所以我们可以对这个数开平方在这个数的开平方数两边开始寻找

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
LL n;
LL gcd(LL a,LL b)
{
	if(b==0)
	{
		return a;
	}
	return gcd(b,a%b);
}
LL lcm(LL a,LL b)
{
	return (a*b)/gcd(a,b);
}
int main()
{
	scanf("%lld",&n);
	LL res=0;
	for(LL i=1;i<=n/i;i++)
	{
		if(n%i==0&&lcm(i,n/i)==n)
		{
			res=i;
		}
	}
	cout<<res<<" "<<n/res<<endl;
	return 0;
}

Tallest Cow - POJ 3263 - Virtual Judge (csgrandeur.cn)

思路:差分,第一次写的时候错了,因为没有考虑一对牛被重复枚举的可能

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e4+10,M=1;
int a[N],b[N];
int n,j,h,r;
typedef pair<int,int> PII;
map<PII,bool> mp;
void check(int l,int r,int c)
{
    b[l]+=c;
    b[r+1]-=c;
}
int main()
{
   cin>>n>>j>>h>>r;
   for(int i=1;i<=n;i++)  a[i]=h;
   for(int i=1;i<=n;i++)  b[i]=a[i]-a[i-1];
   while(r--)
   {
       int x,y;
       cin>>x>>y;
       if(x>y) swap(x,y);
       if(mp[make_pair(x,y)]) continue;
       mp[make_pair(x,y)]=true;
       check(x+1,y-1,-1);
   }
   for(int i=1;i<=n;i++) a[i]=b[i]+a[i-1];
   for(int i=1;i<=n;i++) cout<<a[i]<<endl;
   return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值