做了一下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;
}