刷题记录

· · 个人记录

P1569Generic Cow Protests

题意

### 思路 `dp`+前缀和 设 $dp_i$ 表示前 $i$ 个数可以被分成的最大区间数。 首先如果 $\sum_{i=1}^{n}a_i< 0$,那么一定输出 `Impossible`; 枚举每个点 $i$ 和它前面的点 $j$,如果 $\sum_{k=j}^i\ge 0$,即 $sum_i -sum_{j-1}\ge 0$,说明这个区间是满足的,就可以转移: $$dp_i=\max(dp_i,dp_j+1)$$ - $dp_i$:当前区间的答案。 - $dp_j+1$:本来前 $j$ 段的答案再加上 $j\sim i$ 这段。 ### 代码 ```cpp line-numbers //#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define ll long long #define re register #define il inline #define endl '\n' #define ull unsigned long long #define llt __int128 #define gcd(x,y) __gcd(x,y) #define lcm(x,y) ((x)*(y)/(gcd(x,y))) #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define fff(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout); #define ls (k<<1) #define rs (k<<1|1) #define umap unordered_map #define uset unordered_set #define mmap multimap #define mset multiset #define pb push_back #define pii pair<int,int> #define pll pair<long long,long long> #define psi pair<string,int> #define psl pair<string,long long> #define numpy(a,n) a+1,a+n+1 #define fi first #define se second #define clr(a) memset(a,0,sizeof(a)) #define mem(a,v) memset(a,v,sizeof(a)) #define lowbit(x) (x&(-x)) #define all(s) s.begin(),s.end() #define mkp make_pair #define maxi INT_MAX #define maxl LONG_LONG_MAX #define mini INT_MIN #define minl LONG_LONG_MIN #define sss "--------------------------------------------------" //----------------------------------------------------------------------------- const int N=1005; int a[N],sum[N],dp[N]; signed main(){ // fff("") IOS int n; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; sum[i]=a[i]+sum[i-1]; if(sum[i]) dp[i]=1; } mem(dp,-0x3f3f3f); dp[0]=0; if(sum[n]<0){ cout<<"Impossible"; return 0; } for(int i=1;i<=n;i++){ for(int j=0;j<i;j++){ if(sum[i]-sum[j]>=0){ dp[i]=max(dp[i],dp[j]+1); } } } cout<<dp[n]; return 0; } ``` ## [P11962 [GESP202503 六级] 树上漫步](https://www.luogu.com.cn/problem/P11962) `DFS`+一点优化 ### 题意 树上的一个节点走偶数步可以到达的节点个数。 ### 思路 首先看到题目就知道暴力枚举 $O(n^2)$ 可以拿 $40\times \frac{1}{4}$ 分,具体写法不说。 我们可以先求出每一个节点的深度,随后可以发现**如果第 $i$ 个节点的深度是偶数,那么经过偶数步可以到达深度同为偶数的节点,包括自己,奇数点同理**。所以只要 $O(n)+O(n)+O(n)$ 即可,复杂度 $O(n)$。 ### 代码 ```cpp line-numbers //#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define ll long long #define re register #define lb long double #define il inline #define endl '\n' #define ull unsigned long long #define llt __int128 #define gcd(x,y) __gcd(x,y) #define lcm(x,y) ((x)*(y)/(gcd(x,y))) #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define fff(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout); #define ls (k<<1) #define rs (k<<1|1) #define umap unordered_map #define uset unordered_set #define mmap multimap #define mset multiset #define pb push_back #define pii pair<int,int> #define pll pair<long long,long long> #define psi pair<string,int> #define psl pair<string,long long> #define gc getchar #define numpy(a,n) a+1,a+n+1 #define fi first #define copy(a,b) memcpy(a,b,sizeof(a)) #define se second #define clr(a) memset(a,0,sizeof(a)) #define mem(a,v) memset(a,v,sizeof(a)) #define lowbit(x) (x&(-x)) #define all(s) s.begin(),s.end() #define mkp make_pair #define maxi INT_MAX #define maxl LONG_LONG_MAX #define mini INT_MIN #define minl LONG_LONG_MIN #define debug(x) cerr<<#x<<"="<<(x)<<'\n' #define hmod 212370440130137957ll #define sss "--------------------------------------------------" //----------------------------------------------------------------------------- int n; const int N=2e5+5; int head[N],nxt[N<<1],to[N<<1],cnt=1; il void add(int u,int v){ nxt[++cnt]=head[u]; head[u]=cnt; to[cnt]=v; } int dep[N]; int cnt1,cnt2; void dfs(int u,int fa){ dep[u]=dep[fa]+1; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(v!=fa) dfs(v,u); } } signed main(){ // fff("") IOS cin>>n; for(int i=1;i<n;i++){ int u,v; cin>>u>>v; add(u,v); add(v,u); } dfs(1,0); // for(int i=1;i<=n;i++) cout<<dep[i]<<" "; for(int i=1;i<=n;i++){ if(dep[i]%2==0){ cnt1++; } else cnt2++; } for(int i=1;i<=n;i++){ if(dep[i]%2==0){ cout<<cnt1<<" "; } else cout<<cnt2<<" "; } return 0; } //CODE BY tc291311 Luogu uid1340395 in Windows-VScode ``` ## [P1296 奶牛的耳语](https://www.luogu.com.cn/problem/P1296) ### 题意 找出距离不超过 $d$ 的二元组对数。 ### 思路 考虑暴力枚举每一个数和它后面的数,时间复杂度 $O(n^2)$,$80pts$。 我们可以用 `upper_bound` 函数找出对于每一个 $a_i+d$ 第一个大于它的数,再用这个数减去 $i$ 再 $-1$ 就是第 $i$ 个数可以到达的点,不懂?看看样例: $10 ,12 ,16 ,37 ,40
  1. 第一个大于 20 的数是 37,坐标是 44-1-1=2
  2. 第一个大于 22 的数是 37,坐标是 44-2-1=1

看懂没有?本来从第一个大于 a_i+d 的数到 i 的距离是 x-i+1x 表示为第一个大于 a_i+d 的数的坐标,因为 a_x>a_i+d,所以实际能到的是 x-i,但是自己又不能和自己说话,所以就是 x-i-1 了。

代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define lb long double
#define il inline
#define endl '\n'
#define ull unsigned long long
#define llt __int128
#define gcd(x,y) __gcd(x,y)
#define lcm(x,y) ((x)*(y)/(gcd(x,y))) 
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); 
#define fff(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
#define ls (k<<1)
#define rs (k<<1|1)
#define umap unordered_map
#define uset unordered_set
#define mmap multimap
#define mset multiset
#define pb push_back
#define pii pair<int,int>
#define pll pair<long long,long long>
#define psi pair<string,int>
#define psl pair<string,long long>
#define gc getchar
#define numpy(a,n) a+1,a+n+1
#define fi first
#define copy(a,b) memcpy(a,b,sizeof(a))
#define se second
#define clr(a) memset(a,0,sizeof(a))
#define mem(a,v)    memset(a,v,sizeof(a))
#define lowbit(x) (x&(-x))
#define all(s) s.begin(),s.end()
#define mkp make_pair
#define maxi INT_MAX
#define maxl LONG_LONG_MAX
#define mini INT_MIN
#define minl LONG_LONG_MIN
#define debug(x) cerr<<#x<<"="<<(x)<<'\n' 
#define hmod 212370440130137957ll
#define sss "--------------------------------------------------"
//-----------------------------------------------------------------------------
const int N=1e6+5;
int a[N];
ll ans;
int n,d;
signed main(){
//  fff("")
    IOS
    cin>>n>>d;
    for(int i=1;i<=n;i++)   cin>>a[i];
    sort(numpy(a,n));
    for(int i=1;i<=n;i++){
        ll r=upper_bound(numpy(a,n),a[i]+d)-a;
        ll l=i;
        ans+=(r-l-1);
    }
    cout<<ans;
    return 0;   
}   
//CODE BY tc291311 Luogu uid1340395 in Windows-VScode

P1194 买礼物

kruskal+一点思维

题意

明明需购买 B 样单价均为 A 元的物品,购买第 I 样后再买第 J 样可享优惠价 K_{I,J}K_{I,J}=K_{J,I}0 表示无优惠,可能大于 A)。求购买所有物品的最小总花费。

思路

kruskal 的板子。

目标是把所有节点连接起来,求最小的权值。

先用一个主节点 0 把所有点连接,边权均为 A

再跑一边 kruskal 即可。

代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define lb long double
#define il inline
#define endl '\n'
#define ull unsigned long long
#define llt __int128
#define gcd(x,y) __gcd(x,y)
#define lcm(x,y) ((x)*(y)/(gcd(x,y))) 
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); 
#define fff(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
#define ls (k<<1)
#define rs (k<<1|1)
#define umap unordered_map
#define uset unordered_set
#define mmap multimap
#define mset multiset
#define pb push_back
#define pii pair<int,int>
#define pll pair<long long,long long>
#define psi pair<string,int>
#define psl pair<string,long long>
#define gc getchar
#define numpy(a,n) a+1,a+n+1
#define fi first
#define copy(a,b) memcpy(a,b,sizeof(a))
#define se second
#define clr(a) memset(a,0,sizeof(a))
#define mem(a,v)    memset(a,v,sizeof(a))
#define lowbit(x) (x&(-x))
#define all(s) s.begin(),s.end()
#define mkp make_pair
#define maxi INT_MAX
#define maxl LONG_LONG_MAX
#define mini INT_MIN
#define minl LONG_LONG_MIN
#define debug(x) cerr<<#x<<"="<<(x)<<'\n' 
#define hmod 212370440130137957ll
#define sss "--------------------------------------------------"
//-----------------------------------------------------------------------------
const int N=5e5+5;
struct node{
    int u,v,w;
}a[N];
int ans;
int cnt;
int fa[N];
int find(int u){
    if(u==fa[u])    return u;
    return fa[u]=find(fa[u]);
}
void merge(int u,int v){
    fa[find(u)]=find(v);
}
bool cmp(node x,node y){
    return x.w<y.w;
}
void kruskal(){
    sort(a+1,a+cnt+1,cmp);
    for(int i=1;i<=cnt;i++){
        if(find(a[i].v)==find(a[i].u))  continue;
        merge(a[i].v,a[i].u);
        ans+=a[i].w;
    }
}
signed main(){
//  fff("")
    IOS
    int v,n;
    cin>>v>>n;
    for(int i=1;i<=n;i++){
        a[++cnt].u=0;
        a[cnt].v=i;
        a[cnt].w=v;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int k;
            cin>>k;
            if(k!=0){
                a[++cnt].u=i;
                a[cnt].v=j;
                a[cnt].w=k;
            }
        }
    }
    for(int i=1;i<=cnt;i++){
        fa[i]=i;
    }
    kruskal();
    cout<<ans;
    return 0;   
}   
//CODE BY tc291311 Luogu uid1340395 in Windows-VScode