B Buffoon
判斷最大值是不是第一個數,簽到題。
H Hour for a Run
輸出\(n*m\)的\(10\%\)到\(90\%\),簽到題,注意別用浮點數和ceil,有精度問題。
M Maratona Brasileira de Popcorn
題有點難讀,就是給n個數,m個人,每人分一個連續段,每個數只能分給一個人,每人每秒最多把數字減k,問最少時間。
二分每一段的上界,貪心判斷即可。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int n,m,k,a[N];
bool check(int x){
int c=1;
int tmp=0;
for(int i=1;i<=n;i++){
if(a[i]>x){
return false;
}
if(tmp+a[i]<=x){
tmp+=a[i];
}else{
c++;
tmp=a[i];
}
}
return c<=m;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
int l=1,r=sum;
int ans=0;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
r=mid-1;
ans=mid;
}else{
l=mid+1;
}
}
printf("%d\n",(ans-1)/k+1);
return 0;
}
D Denouncing Mafia
題意相當於給定一棵樹,找出k條鏈使得覆蓋的點最多。
-
考慮貪心,每次肯定拿最長的一條鏈,然后拿走這條鏈后,樹會變成一個森林,下一次再從這些樹中取出最長鏈,再加入一些樹
-
dfs一遍預處理出每個節點對應子樹的最長鏈和刪去最長鏈后得到的森林根節點,用一個優先隊列貪心取即可。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+55;
vector<int> g[N];
int ld[N];
vector<int> ls[N];
int n,k,f;
struct node{
int u,w;
bool operator<(const node& rhs)const{
return w<rhs.w;
}
};
void dfs(int u){
int siz=g[u].size();
if(!siz){
ld[u]=1;
return;
}
int mx=0;
int k=0;
for(int i=0;i<siz;i++){
int v=g[u][i];
dfs(v);
if(ld[v]>mx){
mx=ld[v];
k=v;
}
}
ld[u]=mx+1;
for(int i=0;i<siz;i++){
int v=g[u][i];
if(v!=k){
ls[u].push_back(v);
}
}
int vs=ls[k].size();
for(int j=0;j<vs;j++){
ls[u].push_back(ls[k][j]);
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&k);
for(int i=2;i<=n;i++){
scanf("%d",&f);
g[f].push_back(i);
}
dfs(1);
priority_queue<node> pq;
pq.push({1,ld[1]});
int ans=0;
while(!pq.empty()){
auto t=pq.top();
int u=t.u;
int w=t.w;
pq.pop();
ans+=w;
k--;
if(!k){
break;
}
int siz=ls[u].size();
for(int i=0;i<siz;i++){
pq.push({ls[u][i],ld[ls[u][i]]});
}
}
printf("%d\n",ans);
return 0;
}
L Less Coin Tosses
題意本質就是長度為n的所有01串,0和1個數相同的可以匹配,找出不能匹配的01串個數。
-
先考慮枚舉0(或者1)的個數,這樣的串有\(C_n^i\)個,那么這些串的01個數顯然相同,如果偶數,可以一一匹配,如果是奇數,答案加1。
-
所以本質就是求\(\sum_{i=1}^n C_n^i\%2\),打表找規律,發現有一個遞歸翻倍的常見套路。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll pw[115],f[115];
int cnt;
void init(){
pw[0]=1;
f[0]=pw[0]-1;
for(int i=1;i<=105;i++){
pw[i]=pw[i-1]*2;
f[i]=pw[i]-1;
if(pw[i]>(ll)1e18){
cnt=i;
break;
}
}
}
ll solve(int k,ll n){
if(k==1){
return 2ll;
}
ll mid=pw[k-1]/2;
if(n<=mid){
return solve(k-1,n);
}else{
return 2ll*solve(k-1,n-mid);
}
}
int main(){
init();
scanf("%lld",&n);
int k=lower_bound(f+1,f+1+cnt,n)-f;
ll ans=solve(k,n-f[k-1]);
printf("%lld\n",ans);
return 0;
}
G Getting Confidence
給定\(n*n\)的矩陣,每列選一個數且不能同一行,使得乘積最大。
- 做過類似套路的題目,將數求個對數,然后乘積最大就是和最大,然后網絡流建圖,限制每行每列,跑個最小費用最大流。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int INF=0x3f3f3f3f;
const double DINF=1.0*1e18;
const double eps=1e-8;
struct Edge{
int u,v,w;
double c;
int next;
}e[N];
int ns,n,mt[105][105];
int cnt,head[N];
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w,double c){
e[cnt]=Edge{u,v,w,c,head[u]};
head[u]=cnt++;
e[cnt]=Edge{v,u,0,-c,head[v]};
head[v]=cnt++;
}
double d[N];
int inq[N],s,t,p[N],a[N];
bool bf(int &flow,double &cost){
for(int i=0;i<ns;i++){
d[i]=DINF;
inq[i]=0;
}
d[s]=0;
p[s]=0;
a[s]=INF;
queue<int> q;
q.push(s);
inq[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=false;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].v;
int w=e[i].w;
double c=e[i].c;
if(w>0 && d[v]>d[u]+c){
d[v]=d[u]+c;
p[v]=i;
a[v]=min(a[u],w);
if(!inq[v]){
q.push(v);
inq[v]=1;
}
}
}
}
if(fabs(d[t]-DINF)<eps){
return 0;
}
flow+=a[t];
cost+=d[t]*a[t];
for(int u=t;u!=s;u=e[p[u]].u){
e[p[u]].w-=a[t];
e[p[u]^1].w+=a[t];
}
return 1;
}
void mcmf(int &flow,double &cost){
flow=0;
cost=0.0;
while(bf(flow,cost));
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&mt[i][j]);
}
}
ns=(n+2)*n+2;
s=0,t=ns-1;
init();
for(int i=1;i<=n;i++){
add(s,n*n+i,1,0.0);
}
for(int i=1;i<=n;i++){
add(n*n+n+i,t,1,0.0);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
add(n*n+i,(j-1)*n+i,1,0.0);
add((j-1)*n+i,n*n+n+j,1,-log10(mt[j][i]));
}
}
int flow=0;
double cost=0;
mcmf(flow,cost);
for(int i=n*n+1;i<=n*n+n;i++){
for(int j=head[i];j!=-1;j=e[j].next){
if(e[j].w==0){
printf("%d",(e[j].v-1)/n+1);
if(i==n*n+n){
printf("\n");
}else{
printf(" ");
}
break;
}
}
}
return 0;
}
J Jar of Water Game
題意不清的模擬題...還好隊友什么牌都玩過
n個人,每個人有4張牌,初始指定第k個人有一張萬能牌且從他開始,每次選一張出現次數最少的牌給下一個人,如果有萬能牌且不是剛拿到,必須把萬能牌給下一個人,如果有多個牌出現次數一樣小,給那個值小的。
勝利的狀態定義為手上有4張相同的牌,不能有萬能牌,如果有多少勝利狀態的人,即相同牌值小的勝利。
#include <bits/stdc++.h>
using namespace std;
int idx(char c){
if(c=='A'){
return 1;
}else if(c>='2' && c<='9'){
return c-'0';
}else if(c=='D'){
return 10;
}else if(c=='Q'){
return 11;
}else if(c=='J'){
return 12;
}else if(c=='K'){
return 13;
}else if(c=='X'){
return 14;
}
}
int n,k;
struct node{
int cnt[15];
int tm;
bool has;
}a[1005];
char s[10];
int win(){
int ans=0;
int res=0x3f3f3f3f;
for(int x=1;x<=n;x++){
int mx=0;
int mk=0;
for(int i=1;i<=13;i++){
mx=max(mx,a[x].cnt[i]);
if(a[x].cnt[i]>mx){
mx=a[x].cnt[i];
mk=i;
}
}
if(mx==4 && !a[x].has){
if(mk<res){
res=mk;
ans=x;
}
}
}
return ans;
}
int get(int x){
if(a[x].has && a[x].tm==1){
return 14;
}else{
if(a[x].has){
a[x].tm=1;
}
int mn=0x3f3f3f3f;
for(int i=1;i<=13;i++){
if(!a[x].cnt[i]){
#include <bits/stdc++.h>
using namespace std;
int idx(char c){
if(c=='A'){
return 1;
}else if(c>='2' && c<='9'){
return c-'0';
}else if(c=='D'){
return 10;
}else if(c=='Q'){
return 11;
}else if(c=='J'){
return 12;
}else if(c=='K'){
return 13;
}else if(c=='X'){
return 14;
}
}
int n,k;
struct node{
int cnt[15];
int tm;
bool has;
}a[1005];
char s[10];
int win(){
int ans=0;
int res=0x3f3f3f3f;
for(int x=1;x<=n;x++){
int mx=0;
int mk=0;
for(int i=1;i<=13;i++){
mx=max(mx,a[x].cnt[i]);
if(a[x].cnt[i]>mx){
mx=a[x].cnt[i];
mk=i;
}
}
if(mx==4 && !a[x].has){
if(mk<res){
res=mk;
ans=x;
}
}
}
return ans;
}
int get(int x){
if(a[x].has && a[x].tm==1){
return 14;
}else{
if(a[x].has){
a[x].tm=1;
}
int mn=0x3f3f3f3f;
for(int i=1;i<=13;i++){
if(!a[x].cnt[i]){
continue;
}
mn=min(mn,a[x].cnt[i]);
}
for(int i=1;i<=13;i++){
if(mn==a[x].cnt[i]){
return i;
}
}
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=0;j<4;j++){
int x=idx(s[j]);
a[i].cnt[x]++;
}
a[i].has=false;
a[i].tm=0;
}
a[k].has=true;
int cur=k;
while(true){
if(int w=win()){
printf("%d\n",w);
return 0;
}
int nex=get(cur);
int nt=cur%n+1;
a[cur].cnt[nex]--;
a[nt].cnt[nex]++;
if(nex==14){
a[cur].has=false;
a[cur].tm=0;
a[nt].has=true;
a[nt].tm=0;
}
cur=nt;
}
return 0;
}
continue;
}
mn=min(mn,a[x].cnt[i]);
}
for(int i=1;i<=13;i++){
if(mn==a[x].cnt[i]){
return i;
}
}
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=0;j<4;j++){
int x=idx(s[j]);
a[i].cnt[x]++;
}
a[i].has=false;
a[i].tm=0;
}
a[k].has=true;
int cur=k;
while(true){
if(int w=win()){
printf("%d\n",w);
return 0;
}
int nex=get(cur);
int nt=cur%n+1;
a[cur].cnt[nex]--;
a[nt].cnt[nex]++;
if(nex==14){
a[cur].has=false;
a[cur].tm=0;
a[nt].has=true;
a[nt].tm=0;
}
cur=nt;
}
return 0;
}
