A
太水,略。
B
思路
以下只讨论不能全部放入的情况。
刚开始以为是01背包问题,但是数据太大,而且物品的花费只有两种:(称为)或(称为)。两个可以合并成一个。把从大到小组对合并到中,那最后只剩下个或个,对新得到的按照价值大小排序,从大到小放入背包。
如果为偶数,就尽可能放。如果为奇数,一直放必定会剩下大小为的空间,那就首先把原先中价值最大的放入,转化成为偶数的情况再求解。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,st,ed) for(ll i=st;i<=ed;++i)
const ll N=1E5+10;
ll n,v,ans,cnta,cntb,cnt;
ll answ[N];
struct Node{
ll ti[2],val;
bool operator < (const Node &tmp) const
{
return val>tmp.val;
}
}a[N],b[N];
int main()
{
scanf("%lld %lld",&n,&v);
rep(i,1,n)
{
ll ty,val;
scanf("%lld %lld",&ty,&val);
if(ty==1)
{
a[++cnta].val=val;
a[cnta].ti[0]=i;
}
else
{
b[++cntb].val=val;
b[cntb].ti[0]=i;
}
}
sort(a+1,a+cnta+1);
if(v%2)
{
ans+=a[1].val;
answ[++cnt]=a[1].ti[0];
}
for(ll i=1+v%2;i<=cnta;i+=2)
{
b[++cntb].val=a[i].val+a[i+1].val;
b[cntb].ti[0]=a[i].ti[0];
b[cntb].ti[1]=a[i+1].ti[0];
}
sort(b+1,b+cntb+1);
ll n=min(v/2,cntb);
rep(i,1,n)
{
ans+=b[i].val;
answ[++cnt]=b[i].ti[0];
if(b[i].ti[1])
answ[++cnt]=b[i].ti[1];
}
cout<<ans<<endl;
if(ans)
rep(i,1,cnt)
printf("%lld ",answ[i]);
cout<<endl;
}
C
思路
A和B下三子棋,A先手,非法情况特别多
- A比B多走两步及以上
- B比A多走一步及以上
- A胜利但是和B走的步数是一样的
- B胜利但是比A少走了一步 剩下的不难写。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
int cnta,cntb;
int a[5][5];
string s;
int judge(int val)
{
int ret=0;
rep(i,1,3)
{
int tot=0;
rep(j,1,3)
{
if(a[i][j]==val)
++tot;
}
if(tot==3)
++ret;
}
rep(i,1,3)
{
int tot=0;
rep(j,1,3)
{
if(a[j][i]==val)
++tot;
}
if(tot==3)
++ret;
}
if(a[2][2]==val)
{
if(a[1][1]==val && a[3][3]==val)
++ret;
if(a[1][3]==val && a[3][1]==val)
++ret;
}
return ret;
}
int main()
{
rep(i,1,3)
{
cin>>s;
rep(j,0,2)
{
if(s[j]=='X')
{
a[i][j+1]=1;
++cnta;
}
else if(s[j]=='0')
{
a[i][j+1]=2;
++cntb;
}
else
{
a[i][j+1]=0;
}
}
}
if(cntb>cnta || cntb<cnta-1)
{
puts("illegal");
return 0;
}
if(judge(2) && cnta>cntb)
{
puts("illegal");
return 0;
}
if(judge(1) && cnta==cntb)
{
puts("illegal");
return 0;
}
if(judge(1))
{
puts("the first player won");
return 0;
}
if(judge(2))
{
puts("the second player won");
return 0;
}
if(cnta+cntb==9)
{
puts("draw");
return 0;
}
if(cnta>cntb)
puts("second");
else
puts("first");
}
D
思路
扫一遍字符串,遇到'?'就改成')',按照每个'?'变成')’和变成'(‘的差值(即)作为关键字维护一个大根堆,如果出现了右括号不匹配的情况就取出堆顶元素并将其变为'('(因为是大根堆,所以取堆顶元素能够减去的代价会更多),更新答案。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
typedef long long ll;
const int N=5E4+10;
int m,k,cnt;
int is[N],dis[N];
ll ans;
struct Node{
ll l,r,pos;
bool operator < (const Node &tmp) const
{
return r-l<tmp.r-tmp.l;
}
};
priority_queue<Node> q;
int main()
{
string s;
cin>>s;
s=' '+s;
int n=s.size()-1;
rep(i,1,n)
{
if(s[i]=='(')
++cnt;
if(s[i]=='?')
{
ll l,r;
scanf("%lld %lld",&l,&r);
if(i==1)
{
ans+=l;
s[i]='(';
++cnt;
continue;
}
s[i]=')';
ans+=r;
q.push((Node){l,r,i});
}
if(s[i]==')')
{
if(cnt)
--cnt;
else
{
if(!q.empty())
{
Node cur=q.top();
q.pop();
if(cur.pos==n)
{
cur=q.top();
q.pop();
}
ans-=cur.r;
ans+=cur.l;
s[cur.pos]='(';
++cnt;
}
else
{
cout<<"-1"<<endl;
return 0;
}
}
}
}
if(cnt)
{
cout<<-1<<endl;
return 0;
}
cout<<ans<<endl;
rep(i,1,n)
putchar(s[i]);
putchar('\n');
}