A
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N = 1e2+10;
int a[N];
int main()
{
SIS;
int t;
cin >> t;
while(t--){
int n;
cin >> n;
for(int i=1;i<=n;++i) cin >> a[i];
sort(a+1,a+1+n);
int ans = 0;
for(int i=n;i>1;i--){
if(a[i]==a[1]) break;
ans++;
}
cout << ans << '\n';
}
return 0;
}
B
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 1e5+10;
ll a[N];
ll b[N];
ll mabs(ll x){
return x<0?-x:x;
}
ll min(ll a,ll b){
return a<b?a:b;
}
void solve(){
int n;
cin >> n;
for(int i=1;i<=n;++i) cin >> a[i];
sort(a+1,a+1+n);
int pos = -1;
for(int i=1;i<=n;++i){
if(a[i]<=0){
b[i]=a[i];
}else{
pos = i;
break;
}
}
if(pos==-1){
cout << n << '\n';
return;
}
//pos-1就是个数
ll minn = (1ll<<50);
for(int i=2;i<=pos-1;++i){
minn=min(minn,mabs(b[i]-b[i-1]));
}
if(a[pos]<=minn) cout << pos << '\n';
else cout << pos-1 << '\n';
}
int main()
{
SIS;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
C
比赛的时候想到DP了;
也想到状态转移肯定是要取上下限了;
可惜平时没怎么打树形dp,gg了…
现在来补
通过这题,有了些个人理解;
这题的树形dp就是先处理子节点然后回推父节点的一个过程;(线段树直呼内行,push_up…)
d p [ i ] [ j ] 表 示 当 前 在 节 点 i , j 表 示 取 上 界 或 者 下 界 dp[i][j]表示当前在节点i,j表示取上界或者下界 dp[i][j]表示当前在节点i,j表示取上界或者下界
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 1e5+10;
struct Node{
int l,r;
}a[N];
ll dp[N][2];
struct Edge{
int next,to;
}e[N<<1];
int head[N],cnt,vis[N];
void add(int u,int v){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
ll _abs(ll x){
return x<0?-x:x;
}
void dfs(int cur){
vis[cur]=1;
for(int i=head[cur];i;i=e[i].next){
int to = e[i].to;
if(!vis[to]){
dfs(to);
//树形dp 先搞子节点 再回推父节点
dp[cur][0] += max(_abs(a[to].l-a[cur].l)+dp[to][0],dp[to][1]+_abs(a[to].r-a[cur].l));
dp[cur][1] += max(_abs(a[to].l-a[cur].r)+dp[to][0],dp[to][1]+_abs(a[to].r-a[cur].r));
}
}
}
int main()
{
SIS;
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vis[0]=head[0]=cnt=0;
for(int i=1;i<=n;++i){
vis[i]=head[i]=0;
auto &x = a[i];
cin >> x.l >> x.r;
}
for(int i=1,u,v;i<=n-1;++i){
cin >> u >> v;
add(u,v);
add(v,u);
}
for(int i=0;i<=n+5;++i){
dp[i][0]=dp[i][1]=0;
}
dfs(1);
cout << max(dp[1][0],dp[1][1]) << endl;
}
return 0;
}
D
首先考虑长度相等的情况;
接着考虑包含的情况
可以发现,当我们外面的大圈确定好后;
里面就是已经推出的状态了;
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int factor[N];//factor(i) 表示i这个数的因子个数,比如factor(8)={1,2,4,8}=4
ll f[N];
ll sum;
const ll MOD = 998244353;
int main()
{
SIS;
int n;
cin >> n;
for(int i=1;i<=n;++i){
for (int j=i;j<=n;j+=i) {
factor[j]++;
}
}
sum=f[1]=1;
for(int i=2;i<=n;++i){
f[i]=(sum+factor[i])%MOD;
sum=(sum+f[i])%MOD;
}
cout << f[n] << '\n';
return 0;
}
可以通过线性筛 搞到 O ( n ) O(n) O(n)
如下
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int factor[N];//factor(i) 表示i这个数的因子个数,比如factor(8)={1,2,4,8}=4
int d[N];
ll f[N];
ll sum;
int prime[N];
bool noprime[N];
const ll MOD = 998244353;
int main()
{
SIS;
int n,tot=0;
cin >> n;
factor[1]=1;
for(int i=2;i<=n;++i){
if(!noprime[i]){
d[i]=1;
factor[i]=2;
prime[++tot] = i;
}
for(int j=1;i*prime[j]<=n&&j<=tot;++j){
noprime[i*prime[j]] = 1;
if(i%prime[j]==0){
factor[i*prime[j]]=factor[i]/(d[i]+1)*(d[i]+2);
d[i*prime[j]] = d[i]+1;
break;
}
factor[i*prime[j]]=factor[i]*2;
d[i*prime[j]]=1;
}
}
sum=f[1]=1;
for(int i=2;i<=n;++i){
f[i]=(sum+factor[i])%MOD;
sum=(sum+f[i])%MOD;
}
cout << f[n] << '\n';
return 0;
}
E
思路:对树1跑dfs,对树2用数据结构维护;
Code
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int N = 3e5+10;
typedef pair<int,int> pii;
int in[N],out[N],timer,ans;
vector<int> v1[N];
vector<int> v2[N];
set<pii> s;
//构造dfs序
void dfs1(int u){
in[u]=++timer;
for(auto i : v2[u]){
dfs1(i);
}
out[u]=timer;
}
/*
首先找第一个>in[u]的节点
如果找到了且这个点是u的子孙,那么我们不要u,选择子孙;
如果不存在这样一个点的in[v]>in[u],那么直接添加u
如果找到的点in[v]>in[u],但他不是子孙;那么我们找in[u]的祖先;
如果存在in[u]的祖先,那么把他干掉;否则直接加in[u]
*/
int add(int u){
auto it = s.upper_bound({in[u],u});
if(it!=s.end()&&out[it->second]<=out[u]) return -2;//子孙
if(it==s.begin()) return -1;//不存在祖先和子孙
--it;//试图寻找祖先
int tmp = it->second;
//如果是祖先的话 那么out时间≥out(u)
if(out[tmp]<out[u]) return -1;//不存在祖先和子孙
//存在祖先
s.erase(it);
return tmp;//返回祖先的标记 用于回溯
}
void dfs2(int u){
int ret = add(u);
if(ret!=-2){
s.insert({in[u],u});
}
ans=max(ans,(int)s.size());
for(auto i : v1[u]){
dfs2(i);
}
//回溯
if(ret!=-2){
s.erase({in[u],u});
if(ret!=-1) s.insert({in[ret],ret});
}
}
int main()
{
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
for(int i=1;i<=n;++i){
v1[i].clear();
v2[i].clear();
}
ans = timer = 0;
s.clear();
for(int i=2,father;i<=n;++i){
cin >> father;
v1[father].push_back(i);
}
for(int i=2,father;i<=n;++i){
cin >> father;
v2[father].push_back(i);
}
dfs1(1);
dfs2(1);
cout << ans << '\n';
}
return 0;
}