2024 杭电多校第六场

1005

状压dp,只不过压的是3进制。

模数有坑点,可能模完为0但是方案存在,也要输出。因此多开一个数组表示存不存在。

#include<bits/stdc++.h>
using namespace std;
const int N=500,K=10,LIM=6e4;
const char ch[]={'A','B','C'};
int Mod;
inline int add(int a,int b){return (a+=b)>=Mod?a-Mod:a;}
int n,k,f[N+5][LIM+5];
bool g[N+5][LIM+5];
string op[N+5];
int _3[K+4];
vector<pair<string,int> >ans;
int F(int x,char S)
{
    if(S=='-') x=(x==0)?2:x-1;
    else if(S=='+') x=(x==2)?0:x+1;
    return x;
}
void Kafka()
{
    cin>>n>>k>>Mod;
    for(int i=1;i<=n;++i) cin>>op[i],op[i]=op[i];
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    f[0][0]=1,g[0][0]=1;
    for(int i=1;i<=n;++i) 
    {
        for(int j=0;j<_3[k];++j)
        {
            if(!g[i-1][j]) continue;
            int v=0,tmp=j;
            for(int p=0;p<k;++p,tmp/=3) v+=F(tmp%3,op[i][p])*_3[p]; 
            f[i][j]=add(f[i][j],f[i-1][j]);
            f[i][v]=add(f[i][v],f[i-1][j]);
            g[i][j]|=g[i-1][j];
            g[i][v]|=g[i-1][j];
        }
    }
    ans.clear();
    for(int i=0;i<_3[k];++i) 
    {
        if(!g[n][i]) continue;
        string s="";
        for(int j=k-1,tmp=i;~j;--j,tmp/=3) s=s+ch[tmp%3];
        ans.push_back(make_pair(s,f[n][i]));
    }
    sort(ans.begin(),ans.end());
    for(int i=0,lim=ans.size();i<lim;++i) cout<<ans[i].first<<' '<<ans[i].second<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    _3[0]=1;for(int i=1;i<=K;++i) _3[i]=_3[i-1]*3;
    int T;
    for(cin>>T;T--;) Kafka();
    return 0;
}

 

1007

容易发现答案可以递推,如果当前MEX为i,则一定不能选点权为i的点,但是点权为[0,i-1]的点都要选。

从i到i+1时要加入i点,而加入某点时相当于从该点开始一直往上级节点走,不断加入,直到遇到已经在联通块里的点。

累加答案时考虑当前联通块“边界”的那些点能否往外延申,预处理出dp[i]表示以i为根的子树选出一个连通块的方案。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int P=998244353;
const int N=1e5+505;
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
int n,sum;
int a[N],dp[N],vis[N],fa[N],pos[N],ans[N];
vector<int> e[N];
int pow(int x,int y){
    if (y==0) return 1;
    int tmp=pow(x,y/2);
    tmp=tmp*tmp%P;
    if (y&1) return tmp*x%P;
        else return tmp;
}
void dfs(int u){
    vis[u]=1;
    int res=1;
    for (int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if (vis[v]) continue;
        dfs(v);
        fa[v]=u;
        res=res*dp[v]%P;
        //printf("u=%lld v=%lld dp[v]=%lld res=%lld\n",u,v,dp[v],res);
    }
    dp[u]=res+1;
    vis[u]=0;
}
void add(int u){
    for (int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if (vis[v]) continue;
        if (v==fa[u]) continue;
        sum=sum*dp[v]%P;
    }
}
void merge(int u){
    if (vis[u]) return;
    while(1){
        vis[u]=1;
        add(u);
        if (vis[fa[u]]) break;
        u=fa[u];
    }
    sum=sum*pow(dp[u],P-2)%P;
}
void test(){
    for (int i=1;i<=n;i++)
        printf("dp[%lld]=%lld\n",i,dp[i]);
    for (int i=0;i<=n;i++)
        printf("ans[%lld]=%lld\n",i,ans[i]);
}
void work(){
    n=read();
    for (int i=1;i<=n;i++){
        a[i]=read();
        e[i].clear();
        dp[i]=fa[i]=vis[i]=ans[i]=0;
        pos[a[i]]=i;
    }
    for (int i=1;i<n;i++){
        int u,v;
        u=read(); v=read();
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(pos[0]);
    int res=0;
    ans[0]=sum=dp[pos[0]]-1;
    vis[pos[0]]=1;
    for (int i=1;i<n;i++){
        merge(pos[i]);
        ans[i]=sum;
    }
    
    for (int i=0;i<n;i++)
        res=(res+(ans[i]-ans[i+1]+P)%P*(i+1)%P)%P;
    //test();
    cout << res << endl;
}
signed main()
{
    int T;
    T=read();
    while(T--) work();
    return 0;
}

 

1004

模拟题,有点细节。

首先肯定要保证上课时间和睡觉时间不重叠。

接下来只要维护不困的时间段即可。

#include<bits/stdc++.h>
using namespace std;
const int N =4e5+10;
int n,m,cnt;
int b[N],e[N],s[N],t[N];
struct node{
    int val,op,se,en;
}f[N];
bool cmp(node a,node b){
    if(a.val!=b.val) return a.val<b.val;
    else return a.op<b.op;
}
void solve(){
    cnt=0;
    cin>>n>>m;
    
    for(int i=1;i<=(n+m)*2;i++) f[i]=(node){0,0,0,0};
    for(int i=1;i<=n;i++){
        cin>>b[i]>>e[i];
        f[++cnt]=(node){b[i],2,1,e[i]};
        f[++cnt]=(node){e[i],2,-1,0};
    }
    for(int i=1;i<=m;i++){
        cin>>s[i]>>t[i];
        f[++cnt]=(node){s[i],1,1,t[i]};
        f[++cnt]=(node){t[i],1,-1,0};
    }
    sort(f+1,f+cnt+1,cmp);
    

    int flag=1;
    for(int i=1;i<=cnt;i++){
        if(f[i].op==1&&f[i].se==1){
            if(f[i+1].op==1) continue;
            //f[i+1].op==2
            if(f[i+1].se==-1){
                if(f[i+1].val!=f[i].val) flag=0;
                if(f[i+2].op==2) flag=0;
            }
        }
        if(f[i].op==2&&f[i].se==1){
            if(f[i+1].op==2) continue;
            // sleep
            if(f[i+1].se==-1) flag=0;
            else if(f[i+2].val!=f[i+1].val) {
                flag=0;
            }
        }
    }
    if(!flag) {
        cout<<"No"<<"\n";
        return;
    }
    
    int l=-1,r=-1;
    for(int i=1;i<=cnt;i++){
        if(f[i].op==2&&f[i].se==1) {
    //        cout<<f[i].val<<" class "<<f[i].en<<"\n";
    //        cout<<l<<" "<<r<<"\n";
            if(f[i].val>=l&&f[i].en<=r) { }
            else flag=0;
        }
        if(f[i].op==1&&f[i].se==1){
            l=f[i].en;
            r=l+2*(f[i].en-f[i].val);
    //        cout<<l<<" sleep "<<r<<"\n";
        }
    }
    
    if(!flag) {
        cout<<"No"<<"\n";
    }
    else cout<<"Yes"<<"\n";
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        solve();
    }
}

1003

模拟题

#include<bits/stdc++.h>
using namespace std;
const int N=1e5,dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int n,ans;
set<pair<int,int> >vis;
void Kafka()
{
    cin>>n;
    char s;
    vis.clear();
    int x=0,y=0,d=0,tx,ty;
    ans=1;
    for(int i=1;i<=n;++i)
    {
        cin>>s;
        x+=dx[d],y+=dy[d];
        if(i==1) tx=x,ty=y;
        if(s=='L') d=(d==0)?3:d-1;
        else if(s=='R') d=(d==3)?0:d+1;
        if(vis.find(make_pair(x,y))==vis.end()) vis.insert(make_pair(x,y));
        else ans=min(ans,-1);
    }
    if(!(x==0&&y==0&&x+dx[d]==tx&&y+dy[d]==ty)) ans=min(ans,0);
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int T;
    for(cin>>T;T--;)Kafka();
    return 0;
}

1001

发现只能删度为2的点,且这种点不能超过5个,否则一定无解

那么暴力删点即可

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,deg[N],mx=0,x[N],y[N],vis[N];
vector<int>e[N];
void dfs(int u,int p){
    vis[u]=1;
    mx=max(mx,(int)e[u].size());
    for(auto v:e[u]){
        if(v==p) continue;
        dfs(v,u);
    }
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) e[i].clear(),vis[i]=0,deg[i]=0;
    
    for(int i=1;i<n;i++) {
        cin>>x[i]>>y[i];
        deg[x[i]]++;deg[y[i]]++;
    }
    
    set<int>s;
    for(int i=1;i<=n;i++){
        if(deg[i]==2) s.insert(i);
    }
    if(s.size()>5||s.size()==0){
        cout<<"No"<<"\n";
        return;
    }
    
    for(auto v:s){
        
        for(int i=1;i<=n;i++) e[i].clear(),vis[i]=0;    
    //    cout<<"?? "<<v<<"\n";
        for(int i=1;i<n;i++){
            if(x[i]==v||y[i]==v) continue;
            e[x[i]].push_back(y[i]);
            e[y[i]].push_back(x[i]);    
        }
        
        set<int>num;
        for(int i=1;i<=n;i++){
            if(vis[i]||i==v) continue;
            mx=0;
            dfs(i,0);
            num.insert(mx);
    //        cout<<"mx "<<mx<<"\n";
        }
        
        if( (*num.begin()) + *(num.rbegin()) ==n-3 ){
            cout<<"Yes"<<"\n";
            return;
        }
    }
    cout<<"No"<<"\n";
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        solve();
    }
}

1002

提供一种不同于正解的做法

重新定义菊花图:

菊花图首先是一棵树,其次存在一个点,它指向的点的度数都为1,剩下的都是度数为1的点。

那么在枚举删去某个点u时,只需要:

1.给u的邻点的度数-1(deg[u]--)

2.维护当前度数不为1的点的个数(代码里的non1)

3.维护 指向的点都为1度点的 点的个数(代码里的all1),实现时多开了一个cnt1[ ]表示某个点指向的1度点的个数,如果cnt1[u]==deg[u]且deg[u]>1,则该点是菊花图中心。

4.判定当前剩下的图是否为菊花图需要:all1==non1(说明度数不为1的点都是菊花图中心,则整个图一定是若干个菊花图)

实现时还有一些细节:

1.如果原图本来就是菊花图,把所有点都输出

2.如果原图有两个及两个以上的连通块不是菊花图,则无解

3.原图只有一个连通块不是菊花图,其他都是,这种情况有解,但要注意在枚举删去的点时,要把其他连通块里的点ban掉。

#include<bits/stdc++.h>
using namespace std;
const int N =2e5+5;
int n,m,cnt=0,tot=0,mx=0,deg[N],vis[N],cnt1[N];
vector<int>e[N];
void dfs(int u,int p){
    cnt++;
    vis[u]=1;
    tot+=e[u].size();
    mx=max(mx,(int)e[u].size());
    for(auto v:e[u]){
        if(vis[v]) continue;
        dfs(v,u);
    }
}
int example;
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        deg[i]=0;
        cnt1[i]=0;
        vis[i]=0;
        e[i].clear();
    }
    for(int i=1,u,v;i<=m;i++){
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
        deg[u]++,deg[v]++;
    }
    int G=0,pos=-1;
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            cnt=0,tot=0,mx=0;
            dfs(i,0);
            if( cnt-1==tot/2 && mx==cnt-1) {}// 判断是否是菊花图
            else {
                G++;pos=i;
            }
        }
    }
    
    if(G>=2){
        cout<<-1<<"\n";
        return;
    }
    else if(G==1){
        for(int i=1;i<=n;i++) vis[i]=0;
        dfs(pos,0);
        
        set<int>s;
        int non1=0,all1=0;
        for(int i=1;i<=n;i++){
            if(!vis[i]) continue;
            if(deg[i]>1) non1++;
            for(auto v:e[i]){
                if(e[v].size()==1) cnt1[i]++;
            }
            if(cnt1[i]==(int)e[i].size()) all1++;
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]) continue;
            for(auto v:e[i]){
                deg[v]--;
            }
            int add_all1=0;
            int add_non1=0;
            if(e[i].size()>1) add_non1=-1;
            set<int>newG;
            for(auto v:e[i]){
                if(deg[v]==1){
                    for(auto to:e[v]){
                        if(to==i) continue;
                        cnt1[to]++;
                        if(cnt1[to]==deg[to]&&deg[to]>1) newG.insert(to);
                    }
                    add_non1--;
                }
                else {
                    if(cnt1[v]==deg[v]&&deg[v]>1) newG.insert(v);
                }
            }
            add_all1=newG.size();
            if(all1+add_all1==non1+add_non1) s.insert(i);
            for(auto v:e[i]) {
                deg[v]++;
                if(deg[v]==2){
                    for(auto to:e[v]){
                        if(to==i) continue;
                        cnt1[to]--;
                    }
                }
            }
        }
        if(s.size()==0) cout<<-1<<"\n";
        else {
            for(auto v:s) {
                if(v!=(*s.rbegin()))cout<<v<<" ";
                else cout<<v;
            }
            cout<<"\n";
        }
    }
    else {
        for(int i=1;i<=n;i++) {
            if(i!=n) cout<<i<<" ";
            else cout<<i;
        }
        cout<<"\n";
    }
}
int main(){
//    freopen("1002.in","r",stdin);
//    freopen("lys.out","w",stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        example++;
        solve();
    }
}
/*
9 6
5 4
6 4
4 9
8 7
7 9
7 2
*/

 

posted @ 2024-08-06 11:41  liyishui  阅读(165)  评论(0编辑  收藏  举报