SDKD 2021 Summer Training Series C3 2nd Round

本文探讨了多种算法和数据结构的实际应用,包括字符串匹配、图论、哈希计算等。涉及题目包括最小间隔的字母匹配、因子对称分布、最大独立集问题以及可恢复子字符串计数。同时,还介绍了一个模拟聊天场景的复杂操作处理问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A - Friendship of Frog
题意:两个相同字母的最小间隔
判断:水题

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,minn,N,num=0,flag;
    cin>>N;
    while(N--){
    num++;
    string str;
    cin>>str;
    n=str.length();
    flag=0;
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
        //cout<<str[i]<<str[j]<<endl;
            if(flag==0&&str[i]==str[j])
               {
               minn=j-i;
               flag=1;
               }
            else if(str[i]==str[j])
               minn=min(minn,j-i);
        }
    }
    if(flag==1)
    cout<<"Case #"<<num<<": "<<minn<<endl;
    else
    cout<<"Case #"<<num<<": "<<"-1"<<endl;
    }
}

B - Almost All Divisors
题意:
判断:对于一个数,他所有的因子是对称分布的,最小的与最大的相乘就为该数,次小的与次大的相乘也为该数,依次类推,那么我们只要根据已知条件求得原来的数是多少,然后再判断该数的所有因子除了1和本身是否都在所给信息中存在并且除了1和本身它的因子个数也应等于给出来的n,判断输出即可。

#include<bits/stdtr1c++.h>
using namespace std;
int n,m;
long long int a[100005],b[100005];
int main()
{
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        sort(a+1,a+1+n);
        long long int ans=a[1]*a[n];
        int flag=1;
        for(int i=2;i<=(n+1)/2;i++){
            if(a[i]*a[n-i+1]!=ans){
                flag=0;
                break;
            }
        }
        if(flag==0){
            cout<<-1<<endl;
            continue;
        }
        int num=0;
        for(long long int i=2;i*i<=ans;i++){
            if(ans%i==0){
                if(i*i==ans)num++;
                else num+=2;//必定配对
            }
        }
        if(num!=n)
            cout<<-1<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}

C - Land of Farms
题意:N*M的图中有一些旧农场,现在要建立一些新的农场,如果新的农场覆盖了某一个旧的农场中的一个点,它就必须覆盖整个这个旧农场。现在要建立尽可能多的新农场,使得每个新农场之间都不相邻,求最多能建立多少个新农场。
判断:最大独立集问题,代码先贴在这,其实嘞,我没看懂

#include<cstdio>
using namespace std;
#define M 130
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
char ch[M];
int num[M][M],a[M][M],set[M][M],f[M][M],g[M],p[M],ans;
bool dfs(int size,int dep)
{
    if(!size)
    {
        if(dep>ans)
        {
            ans=dep;
            return 1;
        }
         else return 0;
    }
    for(int i=1;i<=size;i++)
    {
        if(dep+size-i+1<=ans) return 0;
        int u=set[dep][i];
        if(dep+g[u]<=ans) return 0;
        int num=0;
        for(int j=i+1;j<=size;j++)
         if(f[u][set[dep][j]]) set[dep+1][++num]=set[dep][j];
        if(dfs(num,dep+1)) return 1;
    }
    return 0;
}
int main()
{
    int T,n,m,size,id;
    scanf("%d",&T);
    for(int v=1;v<=T;v++)
    {
        scanf("%d%d",&n,&m);//n行m列
        for(int i=0;i<=9;i++) p[i]=0;//用于记录每个古田的地的大小
        id=0;
        for(int i=1;i<=n;i++)
        {//以行做循环
            scanf("%s",ch+1);//把一行作为字符串读入
            for(int j=1;j<=m;j++)//一行第几个字符
            {
                if('0'<=ch[j]&&ch[j]<='9')//如果是数字,就属于古田
                {
                    if(!p[ch[j]-'0'])
                        p[ch[j]-'0']=++id;//相对应的古田地皮量增加
                    num[i][j]=p[ch[j]-'0'];//把古田的位置进行记录,ij是古田,并其值为到此为止该古田的数量
                }
                 else num[i][j]=++id;//
            }
        }
        for(int i=1;i<=id;i++)
         for(int j=1;j<=id;j++)
            f[i][j]=i!=j;//==if i!=j f[i][j]=1 else f[i][j]=0,优先运算级问题
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
         {
             for(int k=0;k<=3;k++)
             {
                 int x=i+dx[k];
                 int y=j+dy[k];
                 if(x<1||x>n||y<1||y>m) continue;
                 f[num[i][j]][num[x][y]]=0;
                f[num[x][y]][num[i][j]]=0;
             }
         }
        ans=0;
        for(int i=id;i>0;i--)
        {
            size=0;
            for(int j=i+1;j<=id;j++)
             if(f[i][j]) set[1][++size]=j;
            dfs(size,1);
            g[i]=ans;
        }
        printf("Case #%d: %d\n",v,ans);
    }
    return 0;
}

D - String
题意:输入M,L和str字符串,计算str的不同“可恢复”子字符串的数量。我们认为S的子字符串是“可恢复的”,当且仅当
(i)长度M*L;
(ii)它可以通过连接S的M个“多样化”子串来构造,其中每个子串的长度为L; 如果两个字符串的每个位置不具有相同的字符,则认为它们是“多样化的”。
判断:哈希算法,也算是二分匹配的一种,这种算法的难点在于key的决定要使得冲突最小,而这道题的代码问题在于mp[x]到底是什么,为什么判断数量到达m就是符合条件

#include<bits/stdtr1c++.h>
#define ull unsigned long long
using namespace std;
char s[100100];
ull hsh[100100],p[100100];
map<ull,int> mp;
//哈希的核心就是一个key一个value对应好,然后防止冲突,这个key的取值是难点
int gethash(int l,int r)//以长度为l分割字符串后,每个子字符串的第一个字符和最后一个字符
{
    return hsh[r]-hsh[l-1]*p[r-l+1];//key值由最后一个字符的hsh和第一个字符往前走一个的hsh以及字符串长度对应的value构成
}

int main()
{
    int m,l;
    while(cin>>m>>l)//M,L
    {
        scanf("%s",s+1);//输入字符串,这里为什么要加一呢
        int num=0;
        int len=strlen(s+1);//取得字符串长度
        p[0]=1;//寄存value的数组
        for(int i=1;i<=len;i++)
        {
            hsh[i]=hsh[i-1]*131+s[i]-'a'+1;//每个字母的一个特定hsh,因为跟前一个hsh挂钩,所以即使字母是一样的,也不会重复
            p[i]=p[i-1]*131;//同样也是与前者挂钩,防止冲突
        }
        for(int i=1;i<=l&&i+m*l<=len;i++)//这个循环这里我还不太明白
        {
            mp.clear();//map归零
            for(int j=i;j<i+m*l;j+=l)//以l为单位
            {
                ull x=gethash(j,j+l-1);//小单位长度为l的子字符串的第一个和最后一个字母去生成key
                mp[x]++;//记录到map里
            }
            if(mp.size()==m)//map里存的此时为总数
                num++;
            for(int j=i+m*l;j+l-1<=len;j+=l)
            {
                ull x=gethash(j,j+l-1);
                mp[x]++;
                ull y=gethash(j-m*l,j-m*l+l-1);
                mp[y]--;
                if(mp[y]==0) mp.erase(y);//把上一个记得y删去
                if(mp.size()==m) num++;//如果mp记录的数据组有m个则
            }
        }
        cout<<num<<endl;//符合要求不重复的子字符串的数量,计算S的不同“可恢复”子字符串的数量。 
    }
    return 0;
}

E - Chat
题意:一个渣男按要求处理女朋友们的故事
判断:第一反应感觉很像链表,但其实吧好像数组也能完成,就是没有什么算法,只要有序列就可以了,细节太多写写很烦
代码贴在这里啦

#include<bits/stdtr1c++.h>
using namespace std;
const int N = 5005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
map<int,int> m;
list<int> l;
int p,top;
__int64 ans[N];
void Add(int u)
{
    if(m[u])
    {
        puts("same priority.");
        return ;
    }
    puts("success.");
    m[u]=p++;
    l.push_back(u);
}
void Close(int u)
{
    if(!m[u])
    {
        puts("invalid priority.");
        return ;
    }
    printf("close %d with %I64d.\n",u,ans[m[u]]);
    m[u]=0;
    l.remove(u);
    if(top==u)
        top=0;
}
void Chat(int w)
{
    if(l.empty())
    {
        puts("empty.");
        return ;
    }
    puts("success.");
    if(top)
        ans[m[top]]+=w;
    else
        ans[m[l.front()]]+=w;
}
void Rotate(int x)
{
    if(x<1||x>l.size())
    {
        puts("out of range.");
        return ;
    }
    puts("success.");
    list<int>::iterator it;
    int i;
    for(i=1,it=l.begin();it!=l.end()&&i<x;it++,i++);
    //printf("%d\n",*it);
    int tmp=*it;
    l.erase(it);
    l.push_front(tmp);
}
void Prior()
{
    if(l.empty())
    {
        puts("empty.");
        return ;
    }
    int i,x,Max=0;
    list<int>::iterator it;
    for(i=1,it=l.begin();it!=l.end();it++,i++)
        if(*it>Max)
            Max=*it,x=i;
    Rotate(x);
}
void Choose(int u)
{
    if(!m[u])
    {
        puts("invalid priority.");
        return ;
    }
    int x;
    list<int>::iterator it;
    for(x=1,it=l.begin();it!=l.end();it++,x++)
        if(*it==u)
            break;
    Rotate(x);
}
void Top(int u)
{
    if(!m[u])
    {
        puts("invalid priority.");
        return ;
    }
    puts("success.");
    top=u;
}
void Untop()
{
    if(!top)
    {
        puts("no such person.");
        return ;
    }
    puts("success.");
    top=0;
}
char s[10];
int main()
{
    int t,n,i,u,w,x;
    scanf("%d",&t);
    while(t--)
    {
        p=1;top=0;
        m.clear();
        l.clear();
        memset(ans,0,sizeof(ans));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            printf("Operation #%d: ",i);
            scanf("%s",s);
            if(!strcmp(s,"Add"))
            {
                scanf("%d",&u);
                Add(u);
            }
            else if(!strcmp(s,"Close"))
            {
                scanf("%d",&u);
                Close(u);
            }
            else if(!strcmp(s,"Chat"))
            {
                scanf("%d",&w);
                Chat(w);
            }
            else if(!strcmp(s,"Rotate"))
            {
                scanf("%d",&x);
                Rotate(x);
            }
            else if(!strcmp(s,"Prior"))
                Prior();
            else if(!strcmp(s,"Choose"))
            {
                scanf("%d",&u);
                Choose(u);
            }
            else if(!strcmp(s,"Top"))
            {
                scanf("%d",&u);
                Top(u);
            }
            else if(!strcmp(s,"Untop"))
                Untop();
        }
        if(top&&ans[m[top]])
            printf("Bye %d: %I64d\n",top,ans[m[top]]);
        list<int>::iterator it;
        for(it=l.begin();it!=l.end();it++)
            if(*it!=top&&ans[m[*it]])
                printf("Bye %d: %I64d\n",*it,ans[m[*it]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值