N - Nunchucks Shop 组合数求不回文的排列
可以发现对于每个i<=n,j<=n,只要i+j==k我们就可以加上i和j的贡献,所以关键的地方就是算贡献,这其实看起来像组合数,但是如果两个排列或者说方案正着和反着是一样也就是回文的话,那么只保留一种就可以,这个也是有公式的
如果n为偶数,i为奇数,那么就是C(n,i)/2,否则就是(C(n,i)+C(n/2,i/2))/2;
知道这个公式,这个题就结束了
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
//const int mod=1e9+7;
const int inf=1e18;
const int N = 1e7+100;
int a[55][55];
int c[55][55];
signed main()
{
//ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
for(int i=0;i<=50;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
for(int i=1;i<=50;i++)
for(int j=0;j<=i;j++)
{
if(i%2==0&&(j&1)) a[i][j]=c[i][j]/2;
else a[i][j]=(c[i][j]+c[i/2][j/2])/2;
}
int ans=0;
int n,k;
cin>>n>>k;
for(int i=0;i<=k&&i<=n;i++)
for(int j=i;j<=k&&j<=n;j++)
{
if(i+j==k)
{
ans+=a[n][i]+a[n][j];
}
}
cout<<ans<<endl;
system("pause");
return 0;
}
D - Yet Another Problem map记录前缀和的位置
如果[L,R]的异或和不为0那么一定是无解的,然后如果[l,r]区间是全0的话就是0步,xr是异或前缀和,pre[i]表示离i最近的j且j<i,满足xr[i]^xr[j-1]=0,如果pre[r]>=l,那么就可以两步完成,因为[l,r]异或和是0,如果[l,r]中有一段区间[x,r]异或和为0,那么剩下的异或和也一定是0;注意一个特判:如果a[l]=0||a[r]=0,那么只需要一步就够了
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=1e9+7;
const int inf=1e18;
const int N = 2e5+100;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int a){return qpow(a,mod-2LL);}
int n,q,a[N],nxt[N],xr[N],sum[N],pre[N];
map<int,int>mp[2];
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>q;
mp[0][0]=0;sum[0]=xr[0]=0;
for(int i=1;i<=n;i++) pre[i]=0,nxt[i]=n+1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
xr[i]=xr[i-1]^a[i];
int bit=i&1;
if(mp[!bit].count(xr[i]))
{
int laspos=mp[!bit][xr[i]];
//cout<<"i="<<i<<" laspos="<<laspos<<" !bit"<<!bit<<" xr[i]="<<xr[i]<<endl;
pre[i]=laspos+1;
//nxt[laspos+1]=min(nxt[laspos+1],i);
}
mp[bit][xr[i]]=i;
}
while(q--)
{
int l,r;
cin>>l>>r;
if((xr[r]^xr[l-1])!=0)
{
cout<<"-1\n";
continue;
}
if(sum[r]-sum[l-1]==0) cout<<"0\n";
else
{
if((r-l+1)&1) cout<<"1\n";
else if(a[l]==0||a[r]==0) cout<<"1\n";
else
{
// cout<<nxt[l]<<" "<<l<<" "<<r<<endl;
if(pre[r]>=l) cout<<"2\n";
else cout<<"-1\n";
}
}
}
system("pause");
return 0;
}
6232. 最小移动总距离 - 力扣(LeetCode) dp
按位置对工厂和机器人排序,然后可以发现对于两个机器人一个位于x,一个位于y且y>x,那么位于y所选的工厂的位置要大于等于x所选的工厂的位置,这样才是最优的,这样这个题就相对来说简单一点了,先预处理出一个d数组,d[i][j]表示前i个机器人到第j个工厂所用的距离之和,f[i][j]表示前i个机器人到前j个工厂所需要的最小的距离之和,这样转移也是可以想一下的,
f[i][j]=min(f[i][j],f[k][j-1]+d[i][j]-d[k][j])
也就是枚举人数和每个工厂,k是前j-1个工厂所治疗的人数,这样第j个工厂就是进了i-k个人,然后看看第j个工厂进多少人才是最优的,这样是可以把所有情况都枚举到的
#define ll long long
struct node
{
int pos,lim;
bool operator<(const node &a)const
{
return pos<a.pos;
}
}fac[205];
class Solution {
public:
long long minimumTotalDistance(vector<int>& robot, vector<vector<int>>& factory) {
int ro[205],n=robot.size(),m=factory.size();
sort(robot.begin(),robot.end());
sort(factory.begin(),factory.end());
for(int i=0;i<robot.size();i++) ro[i+1]=robot[i];
for(int i=0;i<factory.size();i++) fac[i+1].pos=factory[i][0],fac[i+1].lim=factory[i][1];
sort(fac+1,fac+m+1);
ll f[205][205],d[205][205];
for(int j=1;j<=m;j++)
{
d[0][j]=0;
for(int i=1;i<=n;i++)
{
d[i][j]=d[i-1][j]+abs(ro[i]-fac[j].pos);
}
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++) f[i][j]=1e18;
for(int i=0;i<=m;i++) f[0][i]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int lim=fac[j].lim;
for(int k=max(0,i-lim);k<=i;k++)
{
f[i][j]=min(f[i][j],f[k][j-1]+d[i][j]-d[k][j]);
}
}
return f[n][m];
}
};
1475D - Cleaning the Phone 瞎搞或者二分
用了一种比较勉强但是比较合理的思路乱搞过去了,,,
一开始全用类型1,一直加到>=m,如果1全用完 还不行的话就用2再加,用2加到>=m之后就要判断是否可以减去一些1,之后对剩下的2都这样判断,但是其实排完序之后如果当前的这个类型2不行的话以后的就一定不行了,因为是从大到小排序的
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=998244353;
const int inf=1e18;
const int N = 4e5+100;
const double eps=1e-8;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
int getinv(int a){return qpow(a,mod-2LL);}
int t,n,m,a[N],b[N],f[2][N];
int cnt[2]={0,0};
struct node
{
int id,val;
bool operator<(const node &a)const
{
return a.val<val;
}
};
bool cmp(int a,int b)
{
return a>b;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>m;
cnt[0]=cnt[1]=0;
priority_queue<node>q;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
cin>>b[i];
f[b[i]&1][++cnt[b[i]&1]]=a[i];
}
sort(f[0]+1,f[0]+cnt[0]+1,cmp);
sort(f[1]+1,f[1]+cnt[1]+1,cmp);
int sum=0,res=0;
for(int i=1;i<=cnt[1];i++)
{
sum+=f[1][i];res++;
//cout<<"sum="<<sum<<" res="<<res<<" f[1][i]="<<f[1][i]<<" "<<i<<endl;
q.push(node{1,f[1][i]});
if(sum>=m) break;
}
int ma=1;
if(sum<m)
{
for(int i=1;i<=cnt[0];i++)
{
sum+=f[0][i];res+=2;
q.push(node{2,f[0][i]});
if(sum>=m)
{
ma=i+1;
while(!q.empty()&&sum-q.top().val>=m)
{
sum-=q.top().val;res-=q.top().id;q.pop();
}
break;
}
}
}
if(sum<m)
{
cout<<"-1\n";continue;
}
//cout<<sum<<" "<<res<<" "<<ma<<endl;
for(int i=ma;i<=cnt[0];i++)
{
node a=q.top();q.pop();
if(q.empty())
{
q.push(a);break;
}
node b=q.top();q.pop();
if(a.val+b.val<f[0][i])
{
sum+=f[0][i]-a.val-b.val;
q.push(node{2,f[0][i]});
while(!q.empty()&&sum-q.top().val>=m)
{
sum-=q.top().val;res-=q.top().id;q.pop();
}
}
else
{
break;
}
}
cout<<res<<endl;
}
system("pause");
return 0;
}
其实比较正规的解法是二分,对类型1和2从大到小排完序之后枚举使用了多少个1,然后去二分2的使用个数
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=998244353;
const int inf=1e18;
const int N = 4e5+100;
const double eps=1e-8;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
int getinv(int a){return qpow(a,mod-2LL);}
int t,n,m,a[N],b[N],f[2][N],sum[N];
int cnt[2]={0,0};
struct node
{
int id,val;
bool operator<(const node &a)const
{
return a.val<val;
}
};
bool cmp(int a,int b)
{
return a>b;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>m;
cnt[0]=cnt[1]=0;
f[0][0]=f[1][0]=0;
int su=0;
for(int i=1;i<=n;i++) cin>>a[i],su+=a[i];
for(int i=1;i<=n;i++)
{
cin>>b[i];
f[b[i]&1][++cnt[b[i]&1]]=a[i];
}
if(su<m)
{
cout<<"-1\n";continue;
}
sort(f[0]+1,f[0]+cnt[0]+1,cmp);
sort(f[1]+1,f[1]+cnt[1]+1,cmp);
sum[0]=0;
for(int i=1;i<=cnt[0];i++) sum[i]=sum[i-1]+f[0][i];
su=0;
int ans=1e18;
for(int i=0;i<=cnt[1];i++)
{
su+=f[1][i];
int x=m-su;
if(x<=0)
{
ans=min(ans,i);continue;
}
int id=lower_bound(sum+1,sum+cnt[0]+1,x)-sum;
if(id<=cnt[0]) ans=min(ans,id*2LL+i);
}
cout<<ans<<endl;
}
system("pause");
return 0;
}