Codeforces Round #367 (Div. 2)

做了一下CF的模拟赛,排名在3000这样,实际比赛都是在凌晨真蛋疼,做出了A,B两题这样,不过没抢时间,三题排名在1500左右。下次还是参加实际赛好了,名字还是黑的。

A:

水题

B:

二分,我其实没用过STL里的lower_bound和upper_bound,所以这题折腾了很久。

lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于等于值val的位置。

upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一个非递减序列[first, last)中第一个大于val的位置。

C:

这题就是个DP,稍微需要一点技巧,先将所有字符串分为反转和不反转两个,这样用dp[i][0]表示当前字符串不反转的最小值,dp[i][1]表示反转,如果当前字符串大于前一个字符串,就进行状态转移。反转可以用STL里的reverse容器,reverse(s.begin(),s.end())将s反转。

<pre name="code" class="cpp">#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int maxn=1e5+5;
const long long inf=1LL<<60;
int n;
int c[maxn];
long long dp[maxn][2];
string str[maxn][2];

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&c[i]);
	for(int i=0;i<n;i++)
	{	
		cin>>str[i][1];
		str[i][0]=str[i][1];
		reverse(str[i][1].begin(),str[i][1].end());//使用容器reverse反转 
	}
	dp[0][0]=0;dp[0][1]=c[0];
	for(int i=1;i<n;i++)
	{
		for(int j=0;j<2;j++)
		{
			dp[i][j]=inf;
			for(int k=0;k<2;k++)
			{
				if(str[i][j]>=str[i-1][k])
					dp[i][j]=min(dp[i][j],dp[i-1][k]+j*c[i]);
			}
		}
	}
	long long ans=min(dp[n-1][0],dp[n-1][1]);
	if(ans==inf)
		printf("-1\n");
	else
		printf("%I64d\n",ans);
	return 0;
}

D:

这题一开始我用multiset做发现超时,看网上一般是用字典树做,用集合做也可以,但还是要用到字典树的思想。现在要找最大值,数的范围是1e9,所以最多有30位为1,这样我们从前到后一位一位的试,每次贪心尽量取1,这样结果最大。

multiset:

#include<iostream>                                                                            
#include<set>                                                                                 
#include<algorithm>                                                                           
using namespace std;                                                                          
multiset<int> s;                                                                              
multiset<int>::iterator it;                                                                   
                                                                                              
bool check(int a,int b)                                                                       
{                                                                                             
	it=s.lower_bound(a);                                                                         
	if(it==s.end()) return false;                                                                
	if(*it<b)                                                                                    
		return true;                                                                                
	else                                                                                         
		return false;                                                                               
}                                                                                             
int query(int x)                                                                              
{                                                                                             
	int ans=0;                                                                                   
	for(int i=30;i>=0;i--)                                                                       
	{                                                                                            
		int temp=(x>>i)&1;                                                                          
		if(!temp)                //如果x的第i位是0需要改变ans,如果是1最后输出时^x即可              
			ans|=(1<<i);                                                                               
		if(!check(ans,ans+(1<<i)))//比如现在要找10000,可以选的数有10000~11111                      
			ans^=(1<<i);           //找不到就将ans改回                                                 
	}                                                                                            
	return (ans^x);                                                                              
}                                                                                             
                                                                                              
int main()                                                                                    
{                                                                                             
	int n,temp;                                                                                  
	char q[10];                                                                                  
	scanf("%d",&n);                                                                              
	s.insert(0);                                                                                 
	for(int i=0;i<n;i++)                                                                         
	{		                                                                                          
		scanf("%s%d",q,&temp);                                                                      
		if(q[0]=='+')                                                                               
			s.insert(temp);                                                                            
		else if(q[0]=='-')                                                                          
		{                                                                                           
			it=s.find(temp);                                                                           
			s.erase(it);                                                                               
		}                                                                                           
		else                                                                                        
		   	printf("%d\n",query(temp));                                                             
	}                                                                                            
	return 0;                                                                                    
}                                                                                             

字典树:

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=3200000;
int tree[maxn][2],sum[maxn];
int tot=1;

void add(int x)
{
	int now=1;
	for(int i=30;i>=0;i--)
	{
		if(x&(1<<i))
		{
			if(!tree[now][1])
				tree[now][1]=++tot;
			now=tree[now][1];
			sum[now]++;
		}
		else
		{
			if(!tree[now][0])
				tree[now][0]=++tot;
			now=tree[now][0];
			sum[now]++;	
		}  
	} 			       			
}
void del(int x)
{
	
	int now=1;
	for(int i=30;i>=0;i--)
	{
		if(x&(1<<i))
		{
			now=tree[now][1];
			sum[now]--;
		}
		else
		{
			now=tree[now][0];
			sum[now]--;	
		}  
	} 			       	
} 	
int query(int x)
{
	int now=1;
	int ans=0;
	for(int i=30;i>=0;i--)
	{
		if(x&(1<<i))
		{
			if(sum[tree[now][0]])//注意这里求异或,如果本身是1,那就必须是0才行,ans是最后结果 
			{
				ans|=(1<<i);
				now=tree[now][0];
			}
			else
			 	now=tree[now][1];	
		}
		else
		{
			if(sum[tree[now][1]])
			{
				ans|=(1<<i);
				now=tree[now][1];
			}
			else
			 	now=tree[now][0];
		}
	}
	return ans;
}	         
int main()
{
	int n,temp;
	char q[10];
	scanf("%d",&n);
	add(0);
	for(int i=0;i<n;i++)
	{		
		scanf("%s%d",q,&temp);
		if(q[0]=='+')
			add(temp);
		else if(q[0]=='-')
		{
			del(temp);
		}
		else
		   	printf("%d\n",query(temp));
	}
	return 0;
}

E:

这题是要将两个子矩形对换,因为时间限制,只能利用十字链表将原本的矩形连接在一起,这样想交换两个子 矩形就只要交换它们周围一圈的元素的指向即可,子矩形内部不用管的,我们只要关注向下和向右两个方向即可

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1005;
int a[maxn][maxn],val[maxn*maxn],id[maxn][maxn];
int down[maxn*maxn],ri[maxn*maxn];
int n,m,q;

int mov(int mark,int dx,int dy)
{
	while(dx--)
	{
		mark=down[mark];
	}
	while(dy--)
	{
		mark=ri[mark];
	}
	return mark;
}
void print()
{
	int mark=id[0][0];
	mark=mov(mark,1,0);
	int tmark=mark;
	for(int i=1;i<=n;i++)
	{
		mark=tmark;
		tmark=mov(mark,1,0);
		for(int j=1;j<=m;j++)
		{
			mark=mov(mark,0,1);
			printf("%d%s",val[mark],j==m?"\n":" ");
		}
	}	
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	int cnt=0;
	for(int i=0;i<=n;i++)
		for(int j=0;j<=m;j++)
		{
			id[i][j]=++cnt;
			val[cnt]=a[i][j];
		}
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			if(j) ri[id[i][j-1]]=id[i][j];
			if(i) down[id[i-1][j]]=id[i][j];
		}
	}
	int x1,y1,x2,y2,dx,dy;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&dx,&dy);
		int mark1=mov(id[0][0],x1-1,y1-1);//找到矩形坐上方的id 
		int mark2=mov(id[0][0],x2-1,y2-1); 
		int p1,q1,p2,q2;
		int p3,q3,p4,q4;
		p1=mov(mark1,0,1);q1=mov(mark2,0,1);//找到矩形正上方的起点;
		p2=mov(mark1,1,0);q2=mov(mark2,1,0);//找到矩形正左边的起点 
		p3=mov(mark1,dx,1);q3=mov(mark2,dx,1);//找到矩形最后一行的起点 
		p4=mov(mark1,1,dy);q4=mov(mark2,1,dy); //找到矩形最后一列的起点
		for(int i=1;i<=dy;i++)
		{
			swap(down[p1],down[q1]);
			p1 = mov(p1, 0, 1); q1 = mov(q1, 0, 1);
			swap(down[p3],down[q3]);
			p3=mov(p3,0,1);q3=mov(q3,0,1);
		} 
		for(int i=1;i<=dx;i++)
		{
			swap(ri[p2],ri[q2]);
			p2=mov(p2,1,0);q2=mov(q2,1,0);
			swap(ri[p4],ri[q4]);
			p4=mov(p4,1,0);q4=mov(q4,1,0);
		}		
	}
	print();
	return 0;
}





 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值