比赛地址 http://acm.sdibt.edu.cn/vjudge/contest/view.action?cid=2193#overview
A - Bit String Reordering
Sample Input
6 3
1 0 0 1 0 1
1 3 2
7 2
1 1 1 0 0 0 0
4 3
15 14
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 2
1 1
0
1
Sample Output
1
12
7
0
题意:输入n,m,然后输入n个数,要求将这六个数分成m个部分。这m个部分里面都相等,边界与周围不同。相邻位置可以交换,问最少的交换次数。
思路:有两种情况,假设给的m个数是1 3 2,要么最后变成011100,要么变成100011,可以计算两个结果中0和1的个数。会有三种情况(两个结果都符合,各符合一个)。当两个结果都符合时,取最小值。根据结果来交换就比较简单了,设结果数组为c,原数组为a,我们比较对应位置的数是不是相等,相等继续,不相等交换该位置的a[i]和a[i+1](前提是a[i+1]与c[i]相等,如果不相等i++),直到结束为止。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1E9+7;;
const int MM=192600817;
deque <char> q;
string s;
int main()
{
ll a[20],b[20],c[20],d[20],aa[20],n,m,i,j,ans;
while(cin>>n>>m)
{
memset(a,0,sizeof(a));
memset(aa,0,sizeof(aa));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
ll x=0,y=0;
ans=0;
for(i=0; i<n; i++)
{
cin>>a[i];
aa[i]=a[i];
if(a[i]==0)
x++;
else
y++;
}
ll e=0,flag=0,cx=0,cy=0,dx=0,dy=0;
for(i=0; i<m; i++)
{
cin>>b[i];
if(flag==0)
{
for(j=0; j<b[i]; j++)
{
c[e]=0;
d[e]=1;
flag=1;
cx++;
dy++;
e++;
}
}
else
{
for(j=0; j<b[i]; j++)
{
c[e]=1;
d[e]=0;
flag=0;
cy++;
dx++;
e++;
}
}
}
if(cx==x&&cy==y&&dx==x&&dy==y)//两个结果都满足,取最小值
{
ll ans1=0,ans2=0;
ans1=0;
for(i=0;i<n;i++)
{
if(a[i]==c[i])
continue;
else
{
for(j=i+1;j<n;j++)
{
if(a[j]==c[i])
{
swap(a[i],a[j]);
ans1++;
break;
}
else
{
swap(a[i],a[j]);
ans1++;
}
}
}
}
ans2=0;
for(i=0;i<n;i++)
{
if(aa[i]==d[i])
continue;
else
{
for(j=i+1;j<n;j++)
{
if(aa[j]==d[i])
{
swap(aa[i],aa[j]);
ans2++;
break;
}
else
{
swap(aa[i],aa[j]);
ans2++;
}
}
}
}
ans=min(ans1,ans2);
}
else
if(dx==x&&dy==y)//只满足第二个结果
{
ans=0;
for(i=0;i<n;i++)
{
if(aa[i]==d[i])
continue;
else
{
for(j=i+1;j<n;j++)
{
if(aa[j]==d[i])
{
swap(aa[i],aa[j]);
ans++;
break;
}
else
{
swap(aa[i],aa[j]);
ans++;
}
}
}
}
}
else
if(cx==x&&cy==y)//只满足第一个结果
{
ans=0;
for(i=0;i<n;i++)
{
if(aa[i]==c[i])
continue;
else
{
for(j=i+1;j<n;j++)
{
if(aa[j]==c[i])
{
swap(aa[i],aa[j]);
ans++;
break;
}
else
{
swap(aa[i],aa[j]);
ans++;
}
}
}
}
}
cout<<ans<<endl;
}
return 0;
}
B - Miscalculation
Sample Input
1+2*3+4
11
1+2*3+4
13
3
3
1+2*3+4
9
Sample Output
M
L
U
I
题意:给出一个只含有乘除的表达式,有两种方式计算它的值,第一种先做乘法,后做加法,第二种从前往后做,不考虑符号的优先级,在给出一个数n,如果n的值与第一种方法计算的值相等,输出M;如果与第二种计算方法相等,输出L,都相等输出U,都不相等,输出I。关键就是表达式求值。不考虑优先级的比较简单。本题关键就是表达式求值。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1E9+7;;
const int MM=192600817;
deque <char> q;
deque <ll> q2;
string s;
int f()
{
while(!q.empty())
{
char t=q.front();
if(t>='0'&&t<='9')
{
q2.push_back(t-'0');
q.pop_front();
}
else if(t=='+')
{
q.pop_front();
}
else if(t=='*')
{
ll a,b,ans;
char m;
int mm;
q.pop_front();
m=q.front();
b=m-'0';
q.pop_front();
mm=q2.back();
q2.pop_back();
a=mm;
ans=a*b;
q2.push_back(ans);
}
}
ll ans=0;
while(!q2.empty())
{
ll tt=q2.front();
ans+=tt;
q2.pop_front();
}
return ans;
}
int main()
{
ll n,m,e,i,j,x,ans=0;
char c;
while(cin>>s)
{
ll ans1=0,ans2=0;
ll len=s.size();
ll flag=0;
ans1=s[0]-'0';
ll sum=0;
for(i=1; i<len; i++)//从前往后计算表达式
{
if(s[i]>='0'&&s[i]<='9')
{
if(c=='+')
ans1+=(s[i]-'0');
else if(c=='*')
ans1*=(s[i]-'0');
}
else if(s[i]=='+')
c=s[i];
else if(s[i]=='*')
{
c=s[i];
sum++;
}
}
if(sum==len/2)//特判一下全是乘法的情况
{
ans2=1;
for(i=0;i<len;i++)
{
if(s[i]>='0'&&s[i]<='9')
ans2*=s[i]-'0';
}
}
else//考虑优先级的表达式的求法
{
//先把表达式放到1号队列当中,如果不是“×”,就放到2号队列当中,如果是乘号,
//就在2号队列的后面取出一个数,在1号队列前面取出一个数,相乘的结果放到2
//号队列的后面。最后将2号队列里面的数相加。注意char和int类型的转换!
while(!q.empty())
q.pop_front();
while(!q2.empty())
q.pop_front();
for(i=0; i<len; i++)
{
q.push_back(s[i]);
}
ans2=0;
ans2=f();
}
cin>>n;
if(n==ans1&&n==ans2)
cout<<"U"<<endl;
else if(n==ans1)
cout<<"L"<<endl;
else if(n==ans2)
cout<<"M"<<endl;
else
cout<<"I"<<endl;
}
return 0;
}
以上是比赛过程中做出来的。
C Shopping
Sample Input
10 3
3 7
8 9
2 5
10 3
8 9
6 7
2 4
10 0
10 6
6 7
4 5
2 5
6 9
3 5
6 8
1000 8
3 4
6 1000
5 1000
7 1000
8 1000
4 1000
9 1000
1 2
Sample Output
23
19
11
23
2997
题意:要去逛商场,商店是从1到n编号的,按顺序排成一列,然后给一些数(a,b)代表到b商店时必须回到a商店在买一些东西,每个相邻的商店长度为1,出口在n+1的位置上,问,到出口走的最短的长度是多少。
思路:最短的长度是当m等于0时,长度为n+1.用贪心的思想,例如第一组样例,可以走的路线是1->2->7->2->7->出口。其实就是将2 5和3 7改成2 7即可,注意会有一次覆盖多种的情况,将5改成7之后标记一下2 7,2 7以后就用不到了。然后把所有没标记的(y-x)*2相加,最后加上初始值11.
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1E9+7;;
const int MM=192600817;
deque <char> q;
string s;
ll flag[550]={0};
struct AA
{
ll x;
ll y;
}aa[550];
bool cmp(struct AA p,struct AA q)
{
if(p.x==q.x)
return p.y<q.y;
return p.x<q.x;
}
int main()
{
ll n,m,i,j,k,a,b;
while(cin>>n>>m)
{
memset(flag,0,sizeof(flag));
for(i=0;i<m;i++)
{
cin>>aa[i].x>>aa[i].y;
}
ll ans=n+1;
sort(aa,aa+m,cmp);
for(i=0;i<m;i++)
{
if(flag[i]==1)
continue;
ll rr=aa[i].y;
for(j=i+1;j<m;j++)
{
if(aa[j].x<=rr)
{
rr=max(aa[j].y,rr);//括号里一定是rr,如果写成aa[i].y不对,因为rr在变
flag[j]=1;
}
else//没必要一直循环下去
{
break;
}
}
aa[i].y=rr;//最后将aa[i].y更改
}
for(i=0;i<m;i++)
{
if(flag[i]==0)
{
ans+=2*(aa[i].y-aa[i].x);
}
}
cout<<ans<<endl;
}
return 0;
}