怎么大家都这么强啊。。。完全打不过啊。。。
A
二分答案check一下。
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const double eps=1e-6;
int n,k,s[N],c[N];
double tmp[N];
double ans;
int main(){
scanf("%d%d",&n,&k);
for(int i=0; i<n; i++)
scanf("%d",&s[i]);
for(int i=0; i<n; i++)
scanf("%d",&c[i]);
double l=0,r=1000;
while(l<r-eps){
double mid=(l+r)/2;
for(int i=0; i<n; i++){
tmp[i]=1.0*s[i]*(c[i]-mid);
}
sort(tmp,tmp+n);
double ans=0;
for(int i=n-1; i>=k; i--){
ans+=tmp[i];
}
if(ans>=0) l=mid;
else r=mid;
}
printf("%lf\n",l);
return 0;
}
B
膜一下配个方就是pell方程了,这个造题的姿势感觉不是很优美。
m=input()
ans=0
if m<=2:
ans=2
elif m<=6:
ans=6
elif m<=12:
ans=12
elif m<=70:
ans=70
elif m<=84:
ans=84
elif m<=408:
ans=408
if(ans==0):
a=6
b=84
c=0
while 1:
c=b*14-a
if c>=m:
ans=c
break
a=b
b=c
a=12
b=408
c=0
while 1:
c=b*34-a
if c>=m:
if ans>c:
ans=c
break
a=b
b=c
a=2
b=70
c=0
while 1:
c=b*34-a
if c>=m:
if ans>c:
ans=c
break
a=b
b=c
print ans
D
好像把奇数插到偶数里的最优位置是单调的,所以就一个个插就完了。比赛的时候想的是把偶数插到奇数里,可能要维护个单调不增序列什么的,应该也能过吧,没试。
#include <bits/stdc++.h>
using namespace std;
const int maxn=200003;
int n;
int a[maxn];
int rk[maxn];
int mi[maxn<<2];
int lz[maxn<<2];
void pushup(int u){
mi[u]=min(mi[2*u],mi[2*u+1]);
}
void pushdown(int u){
if(lz[u]==0)return;
lz[2*u]+=lz[u];
lz[2*u+1]+=lz[u];
mi[2*u]+=lz[u];
mi[2*u+1]+=lz[u];
lz[u]=0;
}
void build(int u,int l,int r){
lz[u]=0;
if(l==r){
mi[u]=0;
return ;
}
int mid=(l+r)/2;
build(2*u,l,mid);
build(2*u+1,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int ql,int qr,int add){
if(ql>r||qr<l)return;
if(ql<=l&&r<=qr){
lz[u]+=add;
mi[u]+=add;
return;
}
int mid=(l+r)/2;
pushdown(u);
update(2*u,l,mid,ql,qr,add);
update(2*u+1,mid+1,r,ql,qr,add);
pushup(u);
}
int query(int u,int l,int r,int ql,int qr){
if(ql>r||qr<l)return n+1;
if(ql<=l&&r<=qr){
return mi[u];
}
int mid=(l+r)/2;
pushdown(u);
return min(query(2*u,l,mid,ql,qr),query(2*u+1,mid+1,r,ql,qr));
}
struct Bit{
int c[maxn];
int lowbit(int x){
return x&(-x);
}
void update(int x){
while(x){
c[x]++;
x-=lowbit(x);
}
}
int query(int x){
int ret=0;
while(x<=n){
ret+=c[x];
x+=lowbit(x);
}
return ret;
}
}bit;
int main(){
scanf("%d",&n);
long long ans=0;
for(int i=1;i<=n/2;i++){
scanf("%d",&a[i]);
ans+=bit.query(a[i]/2);
bit.update(a[i]/2);
rk[a[i]/2]=i;
}
build(1,1,n/2+1);
for(int i=1;i<=n/2;i++){
update(1,1,n/2+1,i+1,n/2+1,1);
}
for(int i=1;i<=n/2;i++){
ans+=query(1,1,n/2+1,1,n/2+1);
update(1,1,n/2+1,1,rk[i],1);
update(1,1,n/2+1,rk[i]+1,n/2+1,-1);
}
printf("%lld\n",ans);
}
E
二分图带权最大匹配。
#include<bits/stdc++.h>
using namespace std;
int n,w[105][105],nx,ny;
const int INF=1e9;
struct dor{
int x[4];
}a[105],b[105];
int getw(dor a, dor b){
int ans=0;
for(int i=0; i<4; i++){
int flag=0;
for(int j=0; j<4; j++){
if(b.x[j]==a.x[i]) flag=1;
}
ans+=flag;
}
return ans;
}
void init(){
scanf("%d",&n);
nx=n;
ny=n;
for(int i=0; i<n; i++){
for(int j=0; j<4; j++){
scanf("%d",&a[i].x[j]);
}
}
for(int i=0; i<n; i++){
for(int j=0; j<4; j++){
scanf("%d",&b[i].x[j]);
}
}
for(int i=0; i<n; i++)
for(int j=0; j<n; j++){
w[i+1][j+1]=getw(a[i],b[j]);
//cout<<i<<" "<<j<<": "<<w[i+1][j+1]<<endl;
}
}
int linker[105],lx[105],ly[105];
bool visx[105],visy[105];
int d;
int dfs(int x)//完全匹配
{
int y,tmp;
visx[x] = 1;
for(y = 1; y <= ny; y ++)
{
if(!visy[y])
{
tmp = lx[x] + ly[y] - w[x][y];
if(!tmp)
{
visy[y] = 1;
if(linker[y] == -1||dfs(linker[y]))
{
linker[y] = x;
return 1;
}
}
else if(d > tmp)//取最小的不在增广轨中的常数d
d = tmp;
}
}
return 0;
}
int KM()//求最大权匹配
{
int sum,x,i,j;
memset(linker,-1,sizeof(linker));
memset(ly,0,sizeof(ly));
for(i = 1; i <= nx; i ++)
for(j = 1,lx[i] = -INF; j <= ny; j ++)
if(lx[i] < w[i][j])
lx[i] = w[i][j];//初始化为权值最大的边的权值
for(x = 1; x <= nx; x++)
{
while(1)
{
d = INF;//常数d每次都要进行初始化
memset(visx,0,sizeof(visx));//每次dfs都要进行更新
memset(visy,0,sizeof(visy));
if(dfs(x))
break;
for(i = 1; i <= nx; i ++)
if(visx[i])//在增广轨中的x点标减去常数d
lx[i] -= d;
for(i = 1; i <= ny; i ++)
if(visy[i])//在增广轨中的y点标加上常数d
ly[i] += d;
}
}
sum = 0;
for(i = 1; i <= ny; i ++)
if(linker[i]!=-1)
sum += w[linker[i]][i];
return sum;
}
int main(){
init();
printf("%d\n",4*n-KM());
return 0;
}
F
好像做烦了,写了一坨不知道什么的线段树。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=100003;
ll power(ll n,ll p){
ll ans=1;
ll base=n;
while(p){
if(p&1)ans=ans*base%mod;
base=base*base%mod;
p>>=1;
}
return ans;
}
ll inv(ll n){
return power(n,mod-2);
}
int n;
int p[maxn],d[maxn],ord[maxn];
ll lz[maxn<<2],sum[maxn<<2];
void pushup(int u){
sum[u]=(sum[2*u]+sum[2*u+1])%mod;
}
void pushdown(int u){
if(lz[u]==1)return;
sum[2*u]=sum[2*u]*lz[u]%mod;
lz[2*u]=lz[2*u]*lz[u]%mod;
sum[2*u+1]=sum[2*u+1]*lz[u]%mod;
lz[2*u+1]=lz[2*u+1]*lz[u]%mod;
lz[u]=1;
}
void build(int u,int l,int r){
lz[u]=1;
if(l==r){
if(l==1){
sum[u]=1;
}
else sum[u]=0;
return ;
}
int mid=(l+r)/2;
build(2*u,l,mid);
build(2*u+1,mid+1,r);
pushup(u);
}
ll query(int u,int l,int r,int ql,int qr){
if(ql>r||qr<l)return 0;
if(ql<=l&&r<=qr)return sum[u];
int mid=(l+r)/2;
pushdown(u);
ll ret=query(2*u,l,mid,ql,qr);
ret=(ret+query(2*u+1,mid+1,r,ql,qr))%mod;
return ret;
}
void update1(int u,int l,int r,int pos,ll add){
if(pos>r||pos<l)return;
if(l==r){
sum[u]=(sum[u]+add)%mod;
return;
}
int mid=(l+r)/2;
pushdown(u);
update1(2*u,l,mid,pos,add);
update1(2*u+1,mid+1,r,pos,add);
pushup(u);
}
void update2(int u,int l,int r,int ql,int qr,ll mul){
if(ql>r||qr<l)return;
if(ql<=l&&r<=qr){
sum[u]=sum[u]*mul%mod;
lz[u]=lz[u]*mul%mod;
return;
}
int mid=(l+r)/2;
pushdown(u);
update2(2*u,l,mid,ql,qr,mul);
update2(2*u+1,mid+1,r,ql,qr,mul);
pushup(u);
}
ll pw[100003];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&p[i],&d[i]);
ord[i]=d[i];
}
ord[n+1]=0;
sort(ord+1,ord+2+n);
build(1,1,n+1);
ll sum=0;
pw[0]=1;
for(int i=1;i<=n;i++)pw[i]=pw[i-1]*100%mod;
for(int i=1;i<=n;i++){
int pos=lower_bound(ord+1,ord+2+n,d[i])-ord;
ll tmp=query(1,1,n+1,1,pos-1);
tmp=tmp*p[i]%mod;
sum=(sum+tmp*pw[n-i])%mod;
update2(1,1,n+1,pos,n,100);
update2(1,1,n+1,1,pos-1,100-p[i]);
update1(1,1,n+1,pos,tmp);
}
sum=sum*inv(pw[n])%mod;
printf("%lld\n",sum);
}
G
签到。
#include <bits/stdc++.h>
using namespace std;
int main(){
int c,n;
cin>>c>>n;
n/=c;
if(n==0)cout<<"-1\n";
else if(n==1)cout<<1ll*c*c<<endl;
else cout<<1ll*n*(n-1)*c*c<<endl;
}
H
先从后往前dp一下以第i个数开头的上升子序列个数,然后逐位确定。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long double inf=1e18+0.5;
const long long INF=1e18+1.5;
int n;
ll k;
int a[500003];
int ord[500003];
ll dp[500003];
int ans[500003];
int tot=0;
ll c[500003];
int lowbit(int x){
return x&(-x);
}
void update(int x,ll add){
while(x){
long double tmp=c[x];
tmp+=add;
if(tmp>inf)c[x]=INF;
else c[x]=(long long)(tmp+0.5);
x-=lowbit(x);
}
}
ll query(ll x){
ll ret=0;
while(x<=500000){
long double tmp=ret;
tmp+=c[x];
if(tmp>inf)return INF;
else ret=(long long)(tmp+0.5);
x+=lowbit(x);
}
return ret;
}
int main(){
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ord[i]=a[i];
}
sort(ord+1,ord+1+n);
for(int i=n;i>=1;i--){
int pos=lower_bound(ord+1,ord+1+n,a[i])-ord;
ll tmp=query(pos+1);
tmp++;
tmp=min(tmp,INF);
dp[i]=tmp;
update(pos,tmp);
}
bool flag=false;
for(int i=1;i<=n;i++){
if(a[i]<=a[ans[tot]]){
continue;
}
if(k==1){
ans[++tot]=i;
flag=true;
break;
}
if(dp[i]>=k){
k--;
ans[++tot]=i;
}
else {
k-=dp[i];
}
}
if(!flag){
printf("-1\n");
}
else {
printf("%d\n",tot);
for(int i=1;i<=tot;i++)printf("%d%c",ans[i],i==tot?'\n':' ');
}
}
I
枚举最左边的点所在的竖直线,记直线上点的个数是n。这条直线上最多取2个点,取2个点之后就不能取其他点了,这样的集合个数是(n2)(n2),要去除完全重合的点对的情况。如果取一个点,那这个点右上方可以取0或1个点,右下方可以取0或1个点,这样的集合个数是(p+1)∗(q+1)(p+1)∗(q+1),p、q分别为右上方和右下方的点的个数。按x从大到小排序,用树状数组维护一下即可。
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
typedef long long ll;
struct node{
int x,y;
}rec[100003];
bool cmp(node a,node b){
if(a.x==b.x){
return a.y<b.y;
}
return a.x>b.x;
}
int ord[100003];
int c1[100003];
int c2[100003];
int lowbit(int x){
return x&(-x);
}
void update1(int x){
while(x<=100000){
c1[x]++;
x+=lowbit(x);
}
}
int query1(int x){
int ret=0;
while(x){
ret+=c1[x];
x-=lowbit(x);
}
return ret;
}
void update2(int x){
while(x){
c2[x]++;
x-=lowbit(x);
}
}
int query2(int x){
int ret=0;
while(x<=100000){
ret+=c2[x];
x+=lowbit(x);
}
return ret;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&rec[i].x,&rec[i].y);
ord[i]=rec[i].y;
}
sort(ord+1,ord+1+n);
sort(rec+1,rec+1+n,cmp);
ll ans=0;
for(int i=1,j;i<=n;i=j+1){
j=i;
while(j+1<=n&&rec[j+1].x==rec[j].x)j++;
ll x=j-i+1;
ans=(ans+x*(x-1)/2)%mod;
ll tmp=0;
for(int k=i;k<=j;k++){
if(k!=i&&rec[k].y!=rec[k-1].y){
ans=(ans-tmp*(tmp-1)/2+mod)%mod;
tmp=1;
}
else tmp++;
}
ans=(ans-tmp*(tmp-1)/2+mod)%mod;
for(int k=i;k<=j;k++){
int pos=lower_bound(ord+1,ord+1+n,rec[k].y)-ord;
ll tmp=1ll*(query1(pos-1)+1)*(query2(pos+1)+1)%mod;
//cout<<"p: "<<rec[k].x<<' '<<rec[k].y<<' '<<pos<<endl;
//cout<<query1(pos-1)<<' '<<query2(pos+1)<<endl;
ans=(ans+tmp)%mod;
}
for(int k=i;k<=j;k++){
int pos=lower_bound(ord+1,ord+1+n,rec[k].y)-ord;
update1(pos);
update2(pos);
}
}
printf("%lld\n",ans);
}
J
签到。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,p2,p3;
cin>>n>>p2>>p3;
ll ans=1ll<<60;
for(ll i=0;i<=2;i++){
for(ll j=0;j<=2;j++){
ll x=i*2+j*3;
ll c=i*p2+j*p3;
if(x>n)continue;
ans=min(ans,c+(n-x+1)/2*p2);
ans=min(ans,c+(n-x+2)/3*p3);
}
}
cout<<ans<<endl;
}