题目传送门:(比较有意思的一场)
A. Eshag Loves Big Arrays
思路:
最小的数不可能被删除
AC Code
#include<bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int minn=200;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
minn=min(minn,a[i]);
}
int num=0;
for(int i=1;i<=n;i++)
{
if(a[i]!=minn) num++;
}
printf("%d\n",num);
}
//system("pause");
return 0;
}
B. Sifid and Strange Subsequences
题目大意:
删除序列中的一些数,使得剩下的任意两个数之差的绝对值都小于等于剩余序列中最大的那个数。问删除之后的序列最多留下多少个数。
思路:
因为取了绝对值,所以小于等于0的数都可以留下来,且不可能留下两个正整数。那么只要判断最小的那个正整数是否能够留下即可。
AC Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
LL a[N],d[N];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+n);
if(n==1)
{
printf("1\n");
continue;
}
for(int i=1;i<n;i++) d[i]=a[i+1]-a[i];
int res=0,idx=0;
for(int i=1;i<=n;i++)
{
if(a[i]<=0)
{
res++;
idx=i;
}
}
if(idx==0) res=1;
else if(idx!=n)
{
LL ans=a[idx+1];
int flag=0;
for(int i=1;i<idx;i++)
if(d[i]<ans) flag=1;
if(flag==0) res++;
}
printf("%d\n",res);
}
//system("pause");
return 0;
}
C. Parsa’s Humongous Tree
思路:
比赛的时候猜了一手结论,感觉每个点都只可能取到左端点和右端点,然后树型dp即可。至于证明的话,我现在也还没去看官方的题解,也不太会。
AC Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
vector<int>g[N];
LL l[N],r[N]; //每个结点的左端点和右端点
LL maxr[N],maxl[N];
void dfs(int x,int fa)
{
for(int i=0;i<g[x].size();i++)
{
int to=g[x][i];
if(to==fa) continue;
dfs(to,x);
maxr[x]+=max(maxr[to]+abs(r[to]-r[x]),maxl[to]+abs(l[to]-r[x]));
maxl[x]+=max(maxr[to]+abs(r[to]-l[x]),maxl[to]+abs(l[to]-l[x]));
}
return ;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&l[i],&r[i]);
maxr[i]=maxl[i]=0;
g[i].clear();
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
printf("%lld\n",max(maxl[1],maxr[1]));
}
//system("pause");
return 0;
}
D. Kavi on Pairing Duty
题目大意:
给你2*n个点,然后有n个点对,每个点对形成一个区间。任意两个点对需要满足两个关系的其中一个。
1.形成的区间大小相等。
2.一个区间完全被包含于另一个区间之中。
思路:
首先可以想到的是,如果有区间是交叉的,那么两者的长度必然相等,长度小的区间必然在长度大的区间之内。
可以分成四种情况。
1.无交叉无包含
2.有交叉且还有被包含的点,那么我们经过画图之后可以发现,被包含的点肯定是位于中间且是连续的。
第一幅图中中间剩下两对点,第二幅图中中间剩下一对点。那么不难想到dp的思想。只要将dp[n-1]+dp[n-2]+……dp[1]即可,然后用前缀和优化一下。
3.全部都是交叉的情况,这个时候只要求一下n的因数即可。
AC Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=998244353;
const int N=1e6+10;
LL f[N],ans[N];
LL g[N];
int main()
{
int n;
scanf("%d",&n);
f[1]=1;
ans[1]=1;
for(int i=2;i<=n;i++)
{
for(int j=i;j<=n;j=j+i)
g[j]++;
}
for(int i=2;i<=n;i++)
{
f[i]=(1+ans[i-1]+g[i])%mod;
ans[i]=(ans[i-1]+f[i])%mod;
}
printf("%lld\n",f[n]%mod);
//system("pause");
return 0;
}