上海大学的一些补题

目录

A.结构体排序

I.没有字母的数

B.构造一个简单数列

拼接的字符串

排列计数

凤 凰

登山小分队

金玉其外矩阵

思维

map

数学规律

贪心,思维

如何才能穿过传送门

古老的恩尼格玛机


周赛第20届上海大学程序设计联赛夏季赛(校外同步赛)_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

总结:思路出问题了,没有用简单的实现方法,还是因为题做少了,简单实现用少了....

心态出问题了,赶紧放空好,找下一个通过率高的题目,通过率高很多时候不是你的能力问题,是你题目没看清,和理解思路,代码实现的问题

A.结构体排序

几次都是排序中忘记加cmp参数,然后时间可以全部转化为分钟,减少码量

I.没有字母的数

思路:前缀和,暴力

就是这个题找规律,把我心态找爆了,什么都想复杂了,又浪费好多时间

自己想的时候觉得从小到大枚举每个数字的十六进制会超时,所以觉得是找规律,找边界区间,(上次就是这么想)二分答案贪心贪错了,这次又是找边界找的要死,结果规律不简单,前缀和想到了赋值以为是找规律想错了只跑对了前面的小数据

正解:直接暴力数据范围1e6枚举每一数位也才1e6*6,直接转看有没有字母来赋值前缀和

bool check(int x)
{
    while(x)
    {
        if(x%16>9)return 0;
        x/=16;
    }
    return 1;
}
void solved()
{
    int l,r;cin>>l>>r;
    print(cnt[r]-cnt[l-1],'\n');
}
signed main()
{
    for(int i=1;i<=1000000;i++)
        if(check(i))cnt[i]=1;
     
    for(int i=1;i<=1000000;i++)
        cnt[i]+=cnt[i-1];
     
    std::ios::sync_with_stdio(0),cin.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    solved();
    return 0;
}

B.构造一个简单数列

构造,思维题

满足题目性质只要从小到大枚举数字,再把不能作为答案的连续数字存队列里从前往后输出就行


queue<int> q;
        int cnt=1;
        s[1]=a;
        for(int i=1;cnt<=n;i++){
            if(i==a) continue;
            if(__gcd(i,s[cnt])==1)//求最大公约数库函数
{
                s[++cnt]=i;
                while(q.size()){
                    s[++cnt]=q.front(),q.pop();
                }
            }else{
                q.push(i);
            }

拼接的字符串

应该是一道结论题,不知道就硬分情况模拟,很多时候双指针就够用,不用双循环。。。

正解:字符串由前后缀拼成,那么长度之和会大于等于拼接串

void solved()
{
    string a,b;
    cin>>a>>b;
    
    int len1=0,len2=0;
    int i=0,j=0;
    while(a[i]==b[j])i++,j++,len1++;
    int k=a.size()-1,p=b.size()-1;
    while(a[k]==b[p])k--,p--,len2++;
   puts(len1+len2>=a.size()?"YES":"NO");
}

排列计数

通过率很高的数学题,那能咋办,猜结论呗看样例为(2n)!/2直接递推取模输出

凤 凰

所有节点到根节点距离,只要搜索求最大 根节点的子节点的子树+1

void dfs(int i,int fa)
{
    for(auto x:e[i])
    {
        if(x!=fa)
        {t++;dfs(x,i);}
    }
}
void solved()
{
    int n;cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        e[u].pb(v);
        e[v].pb(u);
    }
    
    int mx=0;
    for(auto x:e[1])
    {
        t=0;
        dfs(x,1);
        mx=max(mx,t);
    }
    print(mx+1,'\n');
	;
}

登山小分队

题意:所有叶子节点到根节点1需要的时间

类似凤凰这个

//数据小,可以暴力模拟
vector <int>G[1010];
bool vis[1010];
int f[1010];
void dfs(int u,int fa)
{
    for(auto v:G[u])
    {
        if(v==fa)continue;
        dfs(v,u);
        f[v]=u;
    }
}
int n;
int res;
void solved()
{  
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v;cin>>u>>v;
        G[u].pb(v);G[v].pb(u);
    }   
    vector<int>leave;
 
    //vector只存叶子节点
    for(int i=2;i<=n;i++)
        if(G[i].size()==1)
            leave.pb(i);
     
        //记录图的父亲节点
        dfs(1,-1);
     
//贪心地想只要考虑叶子就行,因为上面的一定会更先一步走完
//模拟走和停的过程,同根的叶子一起走1会停在同一点,vis记录多个人同叶子则continue
    while(1)
    {
       memset(vis,0,sizeof vis);
        bool ok=1;
        for(int i=0;i<leave.size();i++)
        {
            if(leave[i]!=1)
            {
                ok=0;
                break;
            }
        }
        if(ok) break;
        res++;
        for(int i=0;i<leave.size();i++) 
            if(leave[i]!=1)
        {
            if(!vis[leave[i]])
            {
                vis[leave[i]]=1;
                leave[i]=f[leave[i]];
            }
        }
    }
    print(res,'\n');
}

金玉其外矩阵

题意:子矩阵和为负,总矩阵和为正

考虑取模,如果大矩阵刚好能被模掉则无法同时满足题意

否则构造子矩阵左上角正边界,右下角正边界取负-1

int a[510][510];
void solved()
{
    int n, m, h, w;
    cin >> n >> m >> h >> w;
    if (n % h == 0 && m % w == 0) 
    {
        puts("N");
        return;
    }
    puts("Y");
    for (int i = 1; i <= n; i += h)
        for (int j = 1; j <= m; j += w) 
          a[i][j] = 10000000;
    
    for (int i = h; i <= n; i += h)
        for (int j = w; j <= m; j += w)
            a[i][j] = -10000001;
    
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
            cout << a[i][j] << ' ';puts("");
    }
}

“新智认知”杯上海高校程序设计竞赛暨第十七届上海大学程序设计春季联赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

思维

/*
题意:维护原子符串中只选唯一字母的最小字典序串

自己想On维护,只过了20%

正解:直接取答案,维护当前答案和前一个字母的大小关系
*/


map<char,int> mp;
bool vis[500];
void solved()
{
	string s,res;cin>>s;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<s.size();i++)mp[s[i]]++;
    for(int i=0;i<s.size();i++){
        mp[s[i]]--;
        if(!vis[s[i]]){
            while(!res.empty()&&s[i]<res.back()&&mp[res.back()]){
                vis[res.back()]=0;
                res.pop_back();
            }
            res+=s[i];
            vis[s[i]]=1; 
        }
    }
    cout<<res<<'\n';
}
signed main()
{
	//std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

	//cf
	solved();
	return 0;
}

map

/*
新字典序用map存然后比较一下
*/
map<char,int> mp;
void solved()
{
	int n;cin>>n;
    int cnt=0;
    for(int i=1;i<=26;i++)
    {
        cnt++;
        char ch;cin>>ch;
        mp[ch]=cnt;
    }
    while(n--)
    {
        string a,b;cin>>a>>b;
        if(a==b)puts("=");
        else{
            int len=max(a.size(),b.size());
            for(int i=0;i<len;i++)
            {
                if(mp[a[i]]==mp[b[i]])continue;
                else{
                    if(mp[a[i]]>mp[b[i]]){puts(">");break;}
                    else {puts("<");break;}
                }
            }
        }
    }
}

数学规律

const int N = 1e6 + 10,mod=998244353;

/*
规律题

题意:给出数学公式和待求式子,序列唯一

n从1开始枚举分别计算出a1,a2,a3
再求2^n*n!发现b[n]=(2*n+1)*b[n-1]
那么预处理存答案就行
*/
int ans[N];
void solved()
{
    int w,q;cin>>w>>q;
    ans[1]=w;
    for(int i=1;i<=1000000;i++)
        ans[i+1]=(2*i+1)*ans[i]%mod;
	while(q--)
    {
        int x;
        cin>>x;
        print(ans[x],'\n');
    }
}

贪心,思维

const int N = 1e5 + 10;

int a[N],b[N],tmp[N];
map<int,int> mpa,mpb;

/*
贪心和思维

目标是让上下序列最大和最小匹配
那么记录一个序列的下标后,升序排列,

另外一个序列排序后最小值匹配相反的最大值的下标

最后是交换,如果不是目标下标则交换,这里是while因为不是直接交换到答案
*/
void solved()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],tmp[i]=a[i];
	for(int i=1;i<=n;i++)cin>>b[i],mpb[b[i]]=i;
	sort(tmp+1,tmp+n+1);
	sort(b+1,b+n+1);
	for(int i=1;i<=n;i++)
		mpa[tmp[i]]=mpb[b[n-i+1]];
	int ans=0;
	for(int i=1;i<=n;i++){
		while(i!=mpa[a[i]]){
           // printf("%d %d\n",a[i],a[mpa[a[i]]]);
			swap(a[i],a[mpa[a[i]]]);
			ans++;
		}
	}
	print(ans,'\n');
}
signed main()
{
	//std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

	//cf
	solved();
	return 0;
}

牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

如何才能穿过传送门

/*
传送门类题目,本题目保证起点从1开始,且只在正轴,距离也小,直接枚举pos模拟
*/
const int N = 1e6+10;
bool st[N];
unordered_map<int,int> mp;
void solved()
{
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=0;i<m;i++)
    {
        int l,r;cin>>l>>r;
        mp[l]=r,mp[r]=l;
    }
    for(int i=0;i<q;i++)
    {
        int x;cin>>x;st[x]=1;
    }
    
    for(int pos=1;pos<=n;pos++)
    {
        if(mp[pos])pos=mp[pos];
        if(st[pos]){
            puts("NO");return;
        }
    }
    puts("YES");
	;
}

古老的恩尼格玛机

/*
模拟字符转换,mp存一下关系
*/
char s[30];
void solved()
{
    unordered_map<char, char> mp;
    for(int i=1;i<=26;i++)cin>>s[i];
     
    for(int i=1;i<=25;i+=2)mp[s[i]]=s[i+1],mp[s[i+1]]=s[i];
     
    int n;cin>>n;
    while(n--)
    {
        string ss;cin>>ss;
        for(auto&c :ss)
            c=mp[c];
         
        cout<<ss<<" ";
    }
    ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值