思维题

CF690A2

题面

考虑没有钱的情况,可以发现只有 \(n=2^k\) 情况可行。为了最少,显然每个人钱数为 \(0/1\),当有 \(m\) 钱,可以将这 \(m\) 钱分给最后 \(m\) 个人,这样一定会有 \(m\) 人投支持票,第 \(2\sim m+1\) 个人显然可以复制这个操作,所以会投反对票,这样就又回到了没有钱的情况。所以得出结论,找出 \(2^k+2m=n\) 的最小 \(m\) 即可。

CF690A3

题面

直接猜自己的数字是不可猜的,转换一下思路,猜所有人的数字之和在模 \(n\) 意义下的和,令第 \(r\) 个僵尸猜的和模 \(n\)\(r-1\) 即可。

[AGC016E] Poor Turkey

题面

做题关键:“留着你是为了把你炖了”。

因为题目说的是存在可能性,那么本质来说就是问我们能否构造一种不死的方案。这说明每次 \(i/j\) 要死的时候,都会有鸡帮它们挡刀。考虑将按时间从大往小考虑,令 \(f_{i,x}\) 表示如果 \(i\) 要活下来,\(x\) 是否要在某个时间前活下来。用 bitset 维护,最后判断如果 \(i,j\) 均要活下来是否会有冲突即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=410,M=1e5+10;
int n,m,a[M],b[M],flag[N];
bitset<N>f[N];
void solve(){
    read(n),read(m);
    for(int i=1;i<=m;i++){
        read(a[i]),read(b[i]);
    }
    for(int i=1;i<=n;i++){
        f[i][i]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=m;j;j--){
            if(f[i][a[j]]&&f[i][b[j]]){
                flag[i]=1;
            }
            if(f[i][a[j]]){
                f[i][b[j]]=1;
            }
            if(f[i][b[j]]){
                f[i][a[j]]=1;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(!flag[i]&&!flag[j]&&((f[i]&f[j]).none())){
                ans++;
            }
        }
    }
    write_endl(ans);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

CF618F

题面

高考引流题,并没有想象中的难。

\(x=suma-sumb\),一个策略,在 \(x<n\) 时,选择 \(a\) 中的数,反之选择 \(b\) 中的数。可以发现无论什么时刻,\(x\in[0,2n)\),但总共有 \(2n+1\) 个时刻,因为开始选数前也是一个时刻,根据鸽巢原理,必然会有两个时刻 \(x\) 相同,即没有无解情况。这两个相同时刻之间选择的数就是我们要的答案。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e6+10;
int n,a[N],b[N],flag[N];
pii p[N];
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]);
    }
    for(int i=1;i<=n;i++){
        read(b[i]);
    }
    int posa=0,posb=0,delta=0;
    flag[0]=1;
    for(int i=1;i<=n*2;i++){
        if(delta<n){
            delta+=a[++posa];
        }
        else{
            delta-=b[++posb];
        }
        if(flag[delta]){
            write_endl(posa-p[delta].first);
            for(int i=p[delta].first+1;i<=posa;i++){
                write_space(i);
            }
            putchar('\n');
            write_endl(posb-p[delta].second);
            for(int i=p[delta].second+1;i<=posb;i++){
                write_space(i);
            }
            return;
        }
        flag[delta]=1;
        p[delta]=mp(posa,posb);
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

CF505E

题面

看到最大值最小,想到二分答案。证明单调性,如果少砍一下,最大值必然大于等于最优的最大值,证毕。

因为正着操作不方便处理,考虑将操作反过来。操作更改为每一轮后 \(h_i\) 变为 \(h_i-a_i\),操作前 \(h_i\ge a_i\);进行 \(k\) 次操作,每次选择一个 \(h_i\) 变为 \(h_i+p\);要求最终的 \(h_i\) 不小于给定的 \(n\) 个数。因为如果大于给出的 \(a_i\)

贪心考虑,每次选择最容易导致 \(h_i-a_i<0\)\(i\) 加上 \(p\),如果不能使得没有 \(h_i-a_i<0\) 则显然不合法。到最后,将剩余操作次数分配一下,判断能否使所以 \(h_i\) 大于等于 \(a_i\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=1e5+10;
int n,m,k,p,a[N],h[N],num[N],ans,l,r=0x3f3f3f3f;
bool chk(int val){
    priority_queue<pii>q;
    for(int i=1;i<=n;i++){
        if(h[i]+m*a[i]<=val){
            continue;
        }
        q.push(mp(-(val/a[i]),i));
        num[i]=0;
    }
    int cnt=0;
    for(int i=1;i<=m;i++){
        if(q.empty()){
            break;
        }
        for(int j=1;j<=k;j++){
            if(q.empty()){
                break;
            }
            int x=-q.top().first,y=q.top().second;
            q.pop();
            if(x<i){
                return 0;
            }
            num[y]++;
            int w=(val+num[y]*p)/a[y];
            if(w<m){
                q.push(mp(-w,y));
            }
            cnt++;
        }
    }
    for(int i=1;i<=n;i++){
        int w=val+num[i]*p-m*a[i];
        if(h[i]<=w){
            continue;
        }
        int sum=(h[i]-w-1)/p+1;
        cnt+=sum;
        if(cnt>m*k){
            return 0;
        }
    }
    return 1;
}
void solve(){
    read(n),read(m),read(k),read(p);
    for(int i=1;i<=n;i++){
        read(h[i]),read(a[i]);
        l=max(l,a[i]);
        r=max(r,a[i]*m+h[i]);
    }
    while(l<=r){
        int mid=(l+r)>>1;
        if(chk(mid)){
            r=mid-1;
            ans=mid;
        }
        else{
            l=mid+1;
        }
    }
    write_endl(ans);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

CF911F

题面

一个结论:和一个点距离最远的点一定为直径两端点之一。对于直径上的点显然,对于不在直径上的点 \(x\),令 \(y\) 为直径上距离 \(x\) 最近的点,因为距离 \(y\) 最远的点为直径的端点,加上一个 \(dis_{x,y}\),距离 \(x\) 最近的点仍是直径的一个端点。

所以找到直径,先处理不在直径上的点,再处理直径上的点即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10;
int n,rt,mx,dep[N];
vector<int>e[N];
void dfs(int u,int fa){
    if(dep[u]>mx){
        rt=u;
        mx=dep[u];
    }
    for(auto v:e[u]){
        if(v==fa){
            continue;
        }
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
vector<int>line,stk;
int vis[N],dis[N],deg[N];
void find(int u,int fa,int to){
    stk.pb(u);
    if(u==to){
        line=stk;
    }
    for(auto v:e[u]){
        if(v==fa){
            continue;
        }
        find(v,u,to);
    }
    stk.pop_back();
}
void count(int u,int d,int fa){
    if(!vis[u]){
        vis[u]=fa;
        dis[u]=d;
    }
    for(auto v:e[u]){
        if(vis[v]){
            continue;
        }
        count(v,d+1,fa);
    }
}
void solve(){
    read(n);
    for(int i=1;i<n;i++){
        int u,v;
        read(u),read(v);
        e[u].pb(v);
        e[v].pb(u);
    }
    dfs(1,0);
    int rtt=rt;
    mx=0;
    dfs(rt,0);
    find(rt,0,rtt);
    for(int i=0;i<line.size();i++){
        int x=line[i];
        vis[x]=x;
        dis[x]=i;
    }
    for(auto x:line){
        count(x,0,x);
    }
    vector<tuple<int,int,int>>ans;
    queue<int>q;
    ll ans_num=0;
    for(int i=1;i<=n;i++){
        deg[i]=e[i].size();
        if(vis[i]==i){
            continue;
        }
        if(deg[i]==1){
            q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(vis[u]==u){
            continue;
        }
        int top=vis[u];
        if(dis[top]>=line.size()-dis[top]-1){
            ans.pb(make_tuple(u,rt,u));
            ans_num+=dis[u]+dis[top];
        }
        else{
            ans.pb(make_tuple(u,rtt,u));
            ans_num+=dis[u]+line.size()-dis[top]-1;
        }
        for(auto v:e[u]){
            deg[v]--;
            if(deg[v]==1){
                q.push(v);
            }
        }
    }
    while(line.size()>1){
        int u=line.back();
        line.pop_back();
        ans.pb(make_tuple(u,rt,u));
        ans_num+=dis[u];
    }
    write_endl(ans_num);
    for(auto x:ans){
        write_space(get<0>(x)),write_space(get<1>(x)),write_endl(get<2>(x));
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2023-06-29 21:09  luo_shen  阅读(36)  评论(1)    收藏  举报