CodeForces:749(div1)&750(div2)

前言

750AB是水题.
749A小清新也比较水但有一点细节
749B经典的那种需要稍微想想但不难的图论蓝题
749C是裹着图论的贪心题
749D的预处理是魔法操作之前没有见过(据说还可以暴力FWT?)
749E大式子题我直接弃疗

CF450A Jzzhu and Children

Description \text{Description} Description

n n n 个孩子排成队,每个孩子有一个需求 a i a_i ai.
每次给队首的孩子 m m m 个糖果,如果还没有满足需求,该孩子就回到队尾,否则就离开.
求最后一个离开的是谁.

Solution \text{Solution} Solution

水题, ⌈ a i n ⌉ \lceil \dfrac{a_i}{n}\rceil nai 求出每个孩子需要几轮,然后取一个轮数最大即可.
同一轮数取编号最大.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1050;
const double eps=1e-10;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m;
int a[105];
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();m=read();
  for(int i=1;i<=n;i++) a[i]=read();
  int mx=0,id=0;
  for(int i=1;i<=n;i++){
    int o=(a[i]+m-1)/m;
    if(o>=mx){
      mx=o;id=i;
    }
  }
  printf("%d\n",id);
  return 0;
}
/*
3 3
tsy
*/

CF450B Jzzhu and Sequences

Description \text{Description} Description

有一个数列 f i f_i fi,给出 f 1 , f 2 f_1,f_2 f1,f2,对于 i > 2 i>2 i>2,满足 f i = f i − 1 + f i + 1 f_i=f_{i-1}+f_{i+1} fi=fi1+fi+1.
求数列的第 n n n 项.
n ≤ 1 0 9 n\le10^9 n109

Solution \text{Solution} Solution

移项:
f i + 1 = f i − f i − 1 f_{i+1}=f_{i}-f_{i-1} fi+1=fifi1.
矩阵乘法即可.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1050;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m;
struct matrix{
  ll a[3][3];
  int x,y;
  matrix(int xx,int yy):x(xx),y(yy){memset(a,0,sizeof(a));}
  matrix() {memset(a,0,sizeof(a));}
};
matrix mul(matrix u,matrix v){
  matrix res(u.x,v.y);
  for(int k=1;k<=u.y;k++){
    for(int i=1;i<=u.x;i++){
      for(int j=1;j<=v.y;j++) (res.a[i][j]+=u.a[i][k]*v.a[k][j])%=mod;
    }
  }
  return res;
}
matrix ksm(matrix o,int k){
  matrix res(2,2);res.a[1][1]=res.a[2][2]=1;
  while(k){
    if(k&1) res=mul(res,o);
    o=mul(o,o);
    k>>=1;
  }
  return res;
}
matrix tr,ans;
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  ans.a[1][2]=(read()+mod)%mod;ans.a[1][1]=(read()+mod)%mod;
  ans.x=1;ans.y=2;
  n=read();
  if(n<=2){
    printf("%lld\n",ans.a[1][3-n]);return 0;
  }
  tr.x=tr.y=2;
  tr.a[1][1]=1;tr.a[1][2]=1;tr.a[2][1]=mod-1;tr.a[2][2]=0;
  ans=mul(ans,ksm(tr,n-2));
  printf("%lld\n",ans.a[1][1]);
  return 0;
}
/*
3 3
tsy
*/

CF449A Jzzhu and Chocolate

Description \text{Description} Description

给出一个 N × M N \times M N×M 的矩阵,给 K K K 个操作,每次操作可以横/竖切割矩阵,求 K K K 次切割,最大化最小块的面积.

Solution \text{Solution} Solution

显然要尽可能平均的切.
那么答案就是 ⌊ n x ⌋ × ⌊ m k + 2 − x ⌋ \lfloor \dfrac{n}{x}\rfloor \times \lfloor \dfrac{m}{k+2-x}\rfloor xn×k+2xm.
⌊ n x ⌋ \lfloor \dfrac{n}{x}\rfloor xn 只有 O ( n ) O(\sqrt n) O(n ) 中取值,整除分块枚举这些值,然后贪心的让 x x x 尽可能的大即可.
需要开 longlong.
细节上,当 k + 2 − x ≤ 0 k+2-x\le0 k+2x0 时,要当成 1 1 1 处理.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1050;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m,k;
ll ans;
inline void check(int a){
  int b=k+2-a;
  if(b>m) return;
  if(b<=0) b=1;
  ans=max(ans,1ll*(n/a)*(m/b));
  return;
}
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();m=read();k=read();
  if(n+m<k+2){
    printf("-1");return 0;
  }
  for(int i=1;i<=n;){
    check(n/(n/i));i=n/(n/i)+1;
  }
  for(int i=1;i*i<=n;i++){
    if(n%i) continue;
    check(i);check(n/i);
  }
  printf("%lld\n",ans);
  return 0;
}
/*
3 3
tsy
*/

CF449B Jzzhu and Cities

Description \text{Description} Description

n n n 个点, m m m 条带权边的无向图,另外还有 k k k 条特殊边,每条边连接 1 1 1 i i i 。 问最多可以删除这 k k k 条边中的多少条,使得每个点到 1 1 1 的最短距离不变.

Solution \text{Solution} Solution

我的做法是开两个堆,一个堆是 Dijkstra 正常用的堆,第二个堆存所有特殊边,优先从 dij 的堆转移即可.
题解的方法是直接维护最短路的条数,感觉更加直观.

Solution \text{Solution} Solution

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=3e5+100;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m,k;
struct node{
  int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){
  p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;
  return;
}
struct edge{
  int id,val;
  bool operator < (const edge y)const{return val>y.val;}
};
priority_queue<edge>Q;
#define pr pair<ll,int>
#define mkp make_pair
priority_queue<pr,vector<pr>,greater<pr> >q;
ll dis[N];
bool vis[N];
int ans;
void dij(){
  memset(dis,0x3f,sizeof(dis));
  q.push(mkp(0,1));dis[1]=0;
  while(!q.empty()||!Q.empty()){
    int now;
    if(q.empty()||(!Q.empty()&&Q.top().val<q.top().first)){
      now=Q.top().id;int val=Q.top().val;Q.pop();
      if(vis[now]) continue;
      assert(dis[now]>val);
      dis[now]=val;++ans;
    }
    else{now=q.top().second;q.pop();if(vis[now]) continue;}
    vis[now]=1;
    for(int i=fi[now];~i;i=p[i].nxt){
      int to=p[i].to;
      if(dis[to]>dis[now]+p[i].w){
	dis[to]=dis[now]+p[i].w;
	q.push(mkp(dis[to],to));
      }
    }    
  }
  return;
}
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  memset(fi,-1,sizeof(fi));
  n=read();m=read();k=read();
  for(int i=1;i<=m;i++){
    int x=read(),y=read(),w=read();
    addline(x,y,w);addline(y,x,w);
  }
  for(int i=1;i<=k;i++){
    edge o={(int)read(),(int)read()};Q.push(o);
  }
  dij();
  printf("%d\n",k-ans);
  return 0;
}
/*
3 3
tsy
*/

CF449C Jzzhu and Apples

Description \text{Description} Description

给出正整数 n n n,你要把 1 − n 1-n 1n 之间的正整数分成尽可能多组,使得每一组两个数的最大公约数大于1;输出能分成最多组的个数,并按任意顺序输出每组的两个数.

Solution \text{Solution} Solution

朴素做法可以想到枚举 g c d gcd gcd 把所有的倍数尽可能的配对.
考虑为什么这样随便选会不优.
就是当某次配对落单的最后也没有配对,但是如果选择其他某个元素落单,后面却可以配对.
所以我们应该尽可能的选取后面容易配对的.
那么我们每次就令 2 × g 2\times g 2×g 配对,最后在 g = 2 g=2 g=2 的时候全都配对就行了.
这样如果还有落单的,说明这些待定的是奇数个,那么肯定就会有落单的,不可能更优了.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1e5+100;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m,k;
int q[N],st,ed;
bool vis[N],jd[N];
int x[N],y[N],tot;
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();
  for(int i=2;i<=n;i++){
    if(jd[i]) continue;
    for(int j=i+i;j<=n;j+=i) jd[j]=1;
  }
  for(int i=n;i>=2;i--){
    if(jd[i]) continue;
    st=1;ed=0;
    for(int j=i;j<=n;j+=i){
      if(!vis[j]) q[++ed]=j;
    }
    if(ed&1) swap(q[2],q[ed]);
    while(st<ed){
      ++tot;x[tot]=q[st];vis[q[st++]]=1;
      y[tot]=q[st];vis[q[st++]]=1;
    }
  }
  printf("%d\n",tot);
  for(int i=1;i<=tot;i++) printf("%d %d\n",x[i],y[i]);
  return 0;
}
/*
3 3
tsy
*/

CF449D Jzzhu and Numbers

Description \text{Description} Description

给出一个序列 a 1... n a_{1...n} a1...n,求元素按位与结果等于 0 0 0 的非空子集选取方案个数.
n ≤ 1 0 6 , a i ≤ 1 0 6 n\le 10^6,a_i\le 10^6 n106,ai106.

Solution \text{Solution} Solution

神奇的题.
容易想到容斥,设 r e s i res_i resi 为与运算后至少有一个 1 1 1 的方案数.
那么答案就是:
a n s = r e s 0 − r e s 1 + r e s 2 . . . ans=res_0-res_1+res_2... ans=res0res1+res2...
r e s x res_x resx 的值不易求解,所以转而考虑求 f x f_x fx 表示与运算后结果 w w w 满足 w & x = x w\&x=x w&x=x 的方案数.
若有 n u m x num_x numx a i a_i ai 满足 a i & x = x a_i\&x=x ai&x=x ,那么就有
n u m x = 2 n u m x − 1 num_x=2^{num_x}-1 numx=2numx1
也就是只能在这 n u m x num_x numx 个数里选,且不能都不选.
那么关键就是求出 n u m x num_x numx.

首先,对于每个 a i a_i ai,令 n u m a i + + num_{a_i}++ numai++.
然后,按位枚举 k k k ,然后若 x x x 的第 k k k 位是 1 1 1 ,就令 n u m x ( 1 < < ( k − 1 ) ) ← n u m x num_{x^(1<<(k-1))}\gets num_x numx(1<<(k1))numx.(换句话说就是转移到把第 k k k 位扣掉后的数.
为什么这样是对的?
首先,这样转移的显然都是合法元素,且不会遗漏.
关键就是为什么这样不会算重.
因为对于每个数对 ( x , y ) , x & y = x (x,y),x\&y=x (x,y),x&y=x n u m y → n u m x num_y\to num_x numynumx转移路径是唯一的.
比如说 01101 → 00100 01101\to00100 0110100100,就会且只会在枚举第 1 1 1 位时 01101 → 01100 01101\to 01100 0110101100,再在枚举第 4 4 4 位时 01100 → 00100 01100\to 00100 0110000100.

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define double long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e6+100;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
int n,m,k;
int a[N],mi[25],f[N],bit[N];
ll ksm(ll x,ll k){
  ll res(1);
  while(k){
    if(k&1) res=res*x%mod;
    x=x*x%mod;k>>=1;
  }
  return res;
}
int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();
  for(int i=1;i<=n;i++) a[i]=read(),f[a[i]]++;
  mi[0]=1;
  for(int i=1;i<=20;i++) mi[i]=mi[i-1]<<1;
  for(int j=20;j>=0;j--){
    for(int i=0;i<mi[20];i++){
      if(i&mi[j]) f[i^mi[j]]+=f[i];
    }
  }
  for(int i=1;i<mi[20];i++) bit[i]=bit[i-(i&-i)]+1;
  ll ans(0);
  for(int i=0;i<mi[20];i++){
    f[i]=(ksm(2,f[i])+mod-1)%mod;
    if(bit[i]&1) ans+=mod-f[i];
    else ans+=f[i];
    ans%=mod;
  }
  printf("%lld\n",ans);
  return 0;
}
/*
3 3
tsy
*/

CF749E Inversions After Shuffle 题解

数学并不会但可以去看看这个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值