A | B | C | D | E | F |
---|---|---|---|---|---|
√ | √ | √ | ○ | √ |
( √:做出; ●:尝试未做出; ○:已补题 )
题目地址:https://codeforces.com/contest/1363
这一次比赛真是“命途多舛”,A题WA了两发,到半个多小时才写出来,E题WA了四发,C也因为智障错误WA了一次,特别是E卡了好久,结果最后看D的时候已经有了思路,可惜不够时间了。
A Odd Selection
题意:问能不能从一堆数字中找出 x 个并且和为奇数。
思路:统计奇数个数和偶数个数,如果 x 小于等于偶数个数,那么是否存在方案就在于是否存在奇数;否则,选取最多的偶数,是的剩余的 x 为奇数,然后看剩余的 x 是否不大于奇数个数。
本来是很简单的,可以比赛的时候一个地方搞错了,然后就……
代码:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
int x=0,flag=1;
char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
int main()
{
//freopen("input.txt","r",stdin);
int T=read();
while(T--)
{
int n=read(),x=read(),ji=0,ou=0;
REP(i,1,n)
{
if(read()&1) ji++;
else ou++;
}
if(x<=ou) puts(ji>0?"Yes":"No");
else
{
if((x-ou)&1) x-=ou;
else if(ou>0) x-=ou-1;
puts((x&1) && x<=ji?"Yes":"No");
}
}
return 0;
}
B Subsequence Hate
题意:
思路:
代码:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
int x=0,flag=1;
char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=1005;
int f[maxn][2],n;
char s[maxn];
int main()
{
//freopen("input.txt","r",stdin);
int t=read();
while(t--)
{
scanf("%s",s+1);
n=strlen(s+1);
REP(i,0,n+4) f[i][0]=f[i][1]=0;
REP(i,1,n)
{
f[i][0]=f[i-1][0];
f[i][1]=f[i-1][1];
if(s[i]=='0') f[i][0]++;
else f[i][1]++;
}
int ans=1e9;
REP(i,1,n+1)
{
ans=min(ans,f[i-1][1]+f[n][0]-f[i-1][0]);
ans=min(ans,f[i-1][0]+f[n][1]-f[i-1][1]);
}
printf("%d\n",ans);
}
return 0;
}
C Game On Leaves
题意:一颗树,有一个结点为特殊结点,两个人玩游戏,每个人每次只能拿走一个叶子结点和相连的那一条边,谁拿到特殊结点谁就赢,问谁赢。
思路:记录每个结点的度,如果特殊结点的度小于等于1,那么先手必胜(比赛一开始忘记考虑一个结点,也就是度为0的情况了),否则可以证明(以及猜到),当结点个数为奇数时后手必胜,反之先手必胜。
代码:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
int x=0,flag=1;
char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=1005;
int du[maxn];
int main()
{
//freopen("input.txt","r",stdin);
int t=read();
while(t--)
{
int n=read(),x=read();
REP(i,1,n) du[i]=0;
REP(i,1,n-1)
{
int u=read(),v=read();
du[u]++; du[v]++;
}
if(du[x]==1 || n==1) {puts("Ayush"); continue;}
puts(n&1?"Ashish":"Ayush");
}
return 0;
}
D Guess The Maximums
题意:一道交互题。有一个长为 n( n ≤ 1000 n\le 1000 n≤1000) 的数组 A,以及 k 个互不相交的集合 S[],定义 p [ i ] = max j ∉ S i A [ j ] p[i]=\max\limits_{j\notin S_i}A[j] p[i]=j∈/SimaxA[j]。你可以最多询问 12 次,每次给出一个数集 S,评测机会返回 max i ∈ S A [ i ] \max\limits_{i\in S}A[i] i∈SmaxA[i] 。要求求出数组 p 。
思路:比赛的时候通过数据 (1000,12)已经猜到这是一个二分,而且也有了一些思路,可惜E题浪费太多时间没时间想了。其实 p[i] 就是所有下标不在 S[i] 中的 A 中最大的值,我们设 m 为 A 中最大的值,那么最多只有可能只有一个 p[q] 不等于 m,这种情况对应于 S[q] 包含了唯一的最大值的下标。那么我们的目标就是找到这个 q,然后单独处理。找 q 的次数为 logn 次最多为 10,加上求 A 最大值和最后单独处理,正好最多12次询问。
代码:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
int x=0,flag=1;
char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=1005;
int n,k,t,vis[maxn],m,ans[maxn];
vector<int> a[maxn];
char s[maxn];
int getR(int l,int r)
{
int sum=0;
REP(i,l,r) sum+=a[i].size();
printf("? %d ",sum);
REP(i,l,r) REP(j,0,a[i].size()-1) printf("%d ",a[i][j]);
puts(""); fflush(stdout);
return read();
}
int main()
{
//freopen("input.txt","r",stdin);
t=read();
while(t--)
{
n=read(),k=read();
REP(i,1,k) a[i].clear();
REP(i,1,k)
{
int c=read();
while(c--) a[i].push_back(read());
}
printf("? %d ",n);
REP(i,1,n) printf("%d ",i); puts("");
fflush(stdout);
m=read();
REP(i,1,k) ans[i]=m;
int l=1,r=k,mid,m1,m2;
while(l<r)
{
mid=(l+r)>>1;
m1=getR(l,mid);
if(m1==m) r=mid;
else l=mid+1;
}
if(l<=r)
{
printf("? %d ",n-a[l].size());
REP(i,1,n)
{
int flag=0;
REP(j,0,a[l].size()-1) if(a[l][j]==i) flag=1;
if(!flag) printf("%d ",i);
}
puts("");
fflush(stdout);
ans[l]=read();
}
printf("! ");
REP(i,1,k) printf("%d ",ans[i]);
puts("");
fflush(stdout);
scanf("%s",s);
if(strcmp(s,"Correct")) break;
}
return 0;
}
E Tree Shuffling
题意:有一颗根结点为 1 的树,每个结点有个权值 a[i],一个当前状态 b[i] (0/1),以及一个目标状态 c[i] (0/1) 。每次操作可以选择一个结点 u,然后从 u 的子树中选取 k 个结点,把他们的状态打乱随意分配,这一次操作代价为 a[i]*k,问最少的代价,使得所有结点的状态变为目标状态。
思路:对于一个结点管辖的子树,如果它父结点路径上存在一个结点的 a 比它小,那么它的子树的 shuffle 由那个更小的结点来处理更优。所以做法就是:对每个结点 dfs 的时候统计它的子树需要变为0 和需要变为1 的个数,然后如果这个结点的 a 不大于其父结点路径上的所有结点,就及时 shuffle 并累计代价。
比赛的时候一开始想错了,一开始的做法只考虑了两侧之间的处理,而没有想到最小代价要跟整个父结点路径扯上关系,后来是自己写了个数据测才发现的。
代码:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
int x=0,flag=1;
char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=2e5+5;
vector<int> G[maxn];
int n,a[maxn],b[maxn],c[maxn],h[maxn][2];
LL ans;
void dfs(int u,int fa,int minx)
{
minx=min(minx,a[u]);
REP(i,0,G[u].size()-1) if(G[u][i]!=fa) dfs(G[u][i],u,minx);
REP(i,0,G[u].size()-1)
{
int v=G[u][i];
if(v==fa) continue;
h[u][0]+=h[v][0]; h[u][1]+=h[v][1];
}
if(b[u]!=c[u]) h[u][c[u]]++;
if(a[u]<=minx)
{
int x=min(h[u][0],h[u][1]);
ans+=1ll*x*2*a[u];
h[u][0]-=x; h[u][1]-=x;
}
}
int main()
{
//freopen("input.txt","r",stdin);
n=read();
REP(i,1,n) a[i]=read(),b[i]=read(),c[i]=read();
REP(i,1,n-1)
{
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0,1e9+5);
if(h[1][0]!=h[1][1]) puts("-1");
else printf("%lld\n",ans);
return 0;
}
F
题意:
思路:
代码: