AtCoder Regular Contest 105
C - Camels and Bridge
思路:
首先题目N比较小,可以全排。
状态划分:
d p [ i ] dp[i] dp[i]为第i只骆驼离第1只骆驼的距离。
状态转移:
d p [ i ] = m a x ( d p [ i ] , d p [ j ] + l e n ( i , j ) ) , j < i dp[i]=max(dp[i],dp[j]+len(i,j)) ,j<i dp[i]=max(dp[i],dp[j]+len(i,j)),j<i
对于 l e n ( i , j ) len(i,j) len(i,j)为 i i i和 j j j骆驼的合法的最短距离。
要求 l e n ( i , j ) len(i,j) len(i,j),我们可以通过二分求得。
单调性处理:
通过观察可得,对于桥的承重和长度,我们能将其按照长度进行排序,长度相同的按承重排序,最后将承重从后往前取min,使其有单调性,进而可以进行二分。
代码实现:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+7;
struct node{
ll l,v;
}a[N];
ll n,m;
ll dp[20];
ll w[20],vis[20],id[20],sum[20];
ll Ans=1e18;
bool cmp(node x,node y){
if(x.l==y.l) return x.v<y.v;
return x.l<y.l;
}
ll search(ll x){
int l=1,r=m;
ll ans=0;
while(l<=r){
int mid=l+r>>1;
if(a[mid].v>=x){
r=mid-1;
}else{
ans=a[mid].l;
l=mid+1;
}
}
return ans;
}
ll gao(){
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+w[id[i]];
}
for(int i=2;i<=n;i++){
for(int j=i-1;j;j--){
ll tem=sum[i]-sum[j-1];
ll len=search(tem);
dp[i]=max(dp[i],dp[j]+len);
}
}
return dp[n];
}
void dfs(int p){
if(p>n){
Ans=min(Ans,gao());
}
for(int i=1;i<=n;i++){
if(vis[i]) continue;
id[p]=i;
vis[i]=1;
dfs(p+1);
vis[i]=0;
}
}
int main(){
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
for(int i=1;i<=m;i++) scanf("%lld %lld",&a[i].l,&a[i].v);
sort(a+1,a+1+m,cmp);
ll mi=1e18;
for(int i=m;i>=1;i--){
mi=min(mi,a[i].v);
a[i].v=mi;
}
for(int i=1;i<=n;i++){
if(w[i]>mi){
printf("-1\n");
return 0;
}
}
dfs(1);
printf("%lld\n",Ans);
}
D - Let’s Play Nim
思路:
如果为n为奇数,second的先手,那么second只需要每次选硬币最多的包放入first第一个放的盘子里,那么,最后的盘子就会是,一个盘子硬币>所有盘子硬币,易知,这样绝对不会XOR为0,这second获胜。
如果n为偶数,那么first先手,如果相同的数量的硬币的包出现为偶数个,那么second的每次只需选与first相同的包,最后盘子的XOR就会为0,second获胜。否则,first只要把每次选最大包的,那么一个盘子的硬币>所有盘子硬币,这样XOR绝不为0,first获胜。
#include <iostream>
#include <map>
using namespace std;
const int N=1e5+7;
int t;
int n,a[N];
map <int,int> ma;
int main(){
cin>>t;
while(t--){
cin>>n;
ma.clear();
for(int i=1;i<=n;i++) cin>>a[i],ma[a[i]]++;
if(n&1) cout<<"Second\n";
else{
int ac=1;
for(int i=1;i<=n;i++){
if(ma[a[i]]&1) ac=0;
}
if(ac==1) cout<<"Second\n";
else cout<<"First\n";
}
}
}