第3题
给出一个长为n的数组,你每次操作可以将其中的一个数字加一或减一,求最少操作次数让该数组成为一个波形数组。波形数组的判定为,数组中除了第一个和最后一个外的元素a[i],都满足两边的元素同时大于a[i]或小于a[i]。
难度不大,先确定是奇数位为大数还是偶数位为大数。接着从左往右贪心,对每个i=2,3,4,n ,如果 ai与ai-1的大小关系不符合条件,则调整 。最后取个min即可。但我们最开始太着急了,题目没有认真去思考,导致t了好几发。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int b[N],a[N],c[N];
int n;
void solve(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
a[i]=b[i];
c[i]=b[i];
}
long long ans=0;
for(int i=2;i<=n;i++){
if(i%2==0){
//cout<<a[4]<<" "<<a[3]<<endl;
if(a[i]<=a[i-1]) ans+=a[i-1]-a[i]+1,a[i]+=a[i-1]-a[i]+1;
}
else {
if(a[i]>=a[i-1]) ans+=a[i]-a[i-1]+1,a[i]-=a[i]-a[i-1]+1;
}
}
long long res=0;
for(int i=2;i<=n;i++){
if(i%2==0){
if(c[i]>=c[i-1]) res+=c[i]-c[i-1]+1,c[i]-=c[i]-c[i-1]+1;
}
else{
if(c[i]<=c[i-1]) res+=c[i-1]-c[i]+1,c[i]+=c[i-1]-c[i]+1;
}
}
//cout<<res<<" "<<ans<<endl;
printf("%lld\n",min(res,ans));
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
solve();
}
}
第7题
你会得到一棵无向树n节点。保证n是均匀的。您将删除一些边缘(至少1),并且必须让每个其余连接的组件具有偶数个顶点。计算删除满足此类约束的边的方法数,模数998244353.
很容易产生思路,dfs一遍树,找出每个子树下面的节点个数(包括自己本身),如果为偶数的话,这个地方就可以切一刀,然后找出所有的子树节点个数,可以找出最多切几刀,然后再排列组合一下就可以了。
不过不知道为什么我写的一直T,耽误了好长时间,但队友根据我的思路,写了差不多的代码就AC了,好奇怪。
#include<bits/stdc++.h>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
int ans[100005],f[100005],head[500005],num;
struct op
{
int next,to;
};
op g[2000000];
void add(int from,int to)
{
g[num].next=head[from];
g[num].to=to;
head[from]=num++;
}
int dfs(int x)
{
for (int i=head[x]; i!=-1; i=g[i].next)
{
int e=g[i].to;
if(!f[e]){
f[e]=1;
ans[x]=ans[x]+dfs(e);
f[e]=0;
}
}
ans[x]++;
return ans[x];
}
int main()
{
int n,q;
long long cnt,sum;
q=read();
while (q--){
memset(head,-1,sizeof(head));
n=read();
sum==0;
for(int i=1; i<=n-1; i++){
int x,y;
x=read();
y=read();
add(x,y);
add(y,x);
}
f[1]=1;
dfs(1);
if(n%2!=0)
printf("0\n");
else{
cnt=0;
for(int i=1;i<=n;i++){
if(ans[i]%2==0)
cnt=cnt+1;
}
long long ppp=0;
cnt=cnt%998244353;
for (int i=1;i<=cnt-1;i++){
long long kt=1;
for (int j=cnt-1;j>=cnt-i;j--)
kt=(kt*j)%998244353;
for (int j=1;j<=i;j++)
kt=(kt/j)%998244353;
ppp=(ppp+kt)%998244353;
}
printf("%d\n",ppp);
}
}
return 0;
}
队友的代码,感觉差不多。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const long long mod=998244353;
typedef long long ll;
ll f[N],nf[N];
int h[N],e[2*N],ne[2*N],idx,siz[N];
void add(int a,int b){
e[++idx]=b;
ne[idx]=h[a];
h[a]=idx;
}
ll qmi(ll a,ll b){
ll res = 1;
while (b)
{
if (b & 1) res = (ll)res * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return res;
}
int n;
void dfs(int u,int fa){
siz[u]=1;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs(j,u);
siz[u]+=siz[j];
}
}
void solve(){
scanf("%d",&n);
memset(h,-1,sizeof h);
idx=0;
memset(siz,0,sizeof siz);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
//cout<<'@';
//memset(dp,0,sizeof dp);
dfs(1,0);
int res=0;
for(int i=2;i<=n;i++){
if(siz[i]%2==0) res++;
}
ll ans=0;
for(int i=1;i<=res;i++){
ans=(ans+f[res]*nf[i]%mod*nf[res-i]%mod)%mod;
}
//cout<<dp[2][1][1]<<endl;
cout<<ans%mod<<endl;
}
int main()
{
f[0]=1,nf[0]=1;
for(int i=1;i<=N-10;i++){
f[i]=f[i-1]*i%mod;
nf[i]=nf[i-1]%mod*qmi(i,mod-2)%mod;
}
int t;
scanf("%d",&t);
while(t--){
solve();
}
}
第9题
有一个纸条分为n空白网格。对于每个i( i < n)(1≤i<n)网 格i和i+1被视为相邻的。爱丽丝和鲍勃将在大道上玩一个游戏。他们轮流移动。在一个动作中,玩家必须将剩余的空白网格之一涂成黑色,同时保留没有两个黑色网格相邻的规则。当其中一个玩家无法绘制任何网格时,游戏结束,游戏的分数定义为涂成黑色的网格总数。爱丽丝想把分数降到最低,而鲍勃想把分数最大化。鉴于n和开始游戏的一方,找出两个玩家发挥最佳状态时的最终得分。
很明显是博弈论,找规律,但我们可能还是不熟悉,写的代码全部都WA了。看了一下大佬的思路。
我们把涂黑操作想象成剪掉连续的三个格子。如果每个连续段长度都<=2 ,那么结果就确定了。
在此之前,可以发现,Alice 的一种最优策略是:选某个连续段的左数第二个格子涂黑。
Bob 的一种最优策略是:选某个连续段的左数第三个格子涂黑。设f(n) , g(n) 分别为 Alice、Bob 面对长度为n的空纸带时的答案。则有f(n) = g(n-3)+1, g(n) = f(n-3)+2,注意到f(n) = f(n-7)+3, g(n) = g(n-7)+3,因此可以快速算出答案。对于<=7内的边界情况可以枚举以后特判一下。
原来这么简单,但我们当时确实没想到,一直在找答案的规律。
#include<bits/stdc++.h>
using namespace std;
int main(){
int T; cin>>T;
while(T--){
int n; string op; cin>>n>>op;
int ans = n/7*3;
if(op[0]=='A'){
if(n%7>=1) ans++;
if(n%7>=4) ans++;
if(n%7>=6) ans++;
}else{
if(n%7>=1) ans++;
if(n%7>=3) ans++;
if(n%7>=5) ans++;
}
cout<<ans<<"\n";
}
return 0;
}