SMU Summer 2024 Contest Round 4

赛后感言:虽然迟到了一个小时,但是一个小时过了两题,而且第三题思路也很清楚,前两题都是一次过的。

b.H and V - SMUOJ

思路:数据量很少,计算各行各列各有多少黑块,二进制枚举删除那些列哪些列,在用总的减去删去的,如果sun-sun1==k,ans++,最后输出答案就好(这是代码一的内容)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int  N=100010;
#define PII pair<int,int>
char p[10][10];
int a[10];
int b[10];
void solve(){
   int h,w,k;
   cin>>h>>w>>k;
   int sum=0;
   int ans=0;
   for(int i=1;i<=h;i++){
       int nn=0;
       for(int j=1;j<=w;j++){
           cin>>p[i][j];
           if(p[i][j]=='#') nn++,sum++;
       }
       a[i]=nn;
   }
    for(int i=1;i<=w;i++){
        int nn=0;
        for(int j=1;j<=h;j++){
            if(p[j][i]=='#') nn++;
        }
        b[i]=nn;
    }
    for(int i=0;i<(1<<h);i++){
        for(int j=0;j<(1<<w);j++){




            int o1=0;
            int aa[10];
            int bb[10];
            for(int l=0;l<h;l++){
                if(((i>>l)&1)==1) aa[o1++]=l+1;
            }
            int o2=0;
            for(int l=0;l<w;l++){
                if(((j>>l)&1)==1) bb[o2++]=l+1;
            }
//            cout<<o1<<o2<<endl;
            int sum1=0;
            for(int g=0;g<o1;g++){
                for(int v=0;v<o2;v++){
                    if(p[aa[g]][bb[v]]=='#') sum1--;
                }
            }
            for(int g=0;g<o1;g++) sum1+=a[aa[g]];
            for(int g=0;g<o2;g++) sum1+=b[bb[g]];
            if(sum-sum1==k) ans++;







//化简的二进制求法
//
//int n,m,k;
//cin>>n>>m>>k;
//int ans=0;
//bool ar[n][m];
//for(int i=0;i<n;i++)for(int j=0;j<m;j++){
//char x;cin>>x;
//ar[i][j]= x == '#';
//}
// for(int i=0;i<(1<<n);i++){
//       for(int j=0;j<(1<<m);j++){
//            int cnt=0;
//           for(int x=0;x<n;x++){
//                for(int y=0;y<m;y++){
//                    if(ar[x][y]&&(i&(1<<x))&&(j&(1<<y)))cnt++;
//                }
//           }
//            if(cnt==k)ans++;
//       }
//   }
        }
    }
    cout<<ans<<endl;

}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t -- ){
        solve();
    }
    return 0;
}

c.Moving Piece - SMUOJ

题解:通过案例推倒,我们发现这是一定存在循环的,于是我们对每一个点求它出现过的循环节,将每一次周期当中出现过的数存入v[i]当中,用sum存储一个周期的价值,如果该周期sum<0,则最大值一定出现在第一次循环当中,如果sum>0,则最大值一定出现在最后一个无论是否完整的周期当中,最后做一些细节处理即可

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
int n,k;
int p[5010],c[5010],mp[5010];
//mp记录当前循环经过了哪些点
int sum[5010];
vector<int>v[5010];
//第i次循环当中出现的数
void solve(){
    cin>>n>>k;
    int ans=-(1e9+10);
    for(int i=1;i<=n;i++) cin>>p[i];
    for(int i=1;i<=n;i++) cin>>c[i];
    for(int i=1;i<=n;i++){
        memset(mp,0,sizeof mp);
        int now=i;
        while(1){//查找周期
            now=p[now];
            if(mp[now]) break;
            mp[now]=1;
            sum[i]+=c[now];
            v[i].push_back(c[now]);
        }
        int l=v[i].size();
        int d=k/l;
        int m=k%l;
        now=0;//一标二用,记录循环中出现过的答案
        if(sum[i]>0){//可以多次循环累计,且最大值一定出现在最后一次完整或不完整的循环
            if(m==0){
                now=(d-1)*sum[i];
                m=l;
            }
            else now=d*sum[i];
            for(int j=0;j<m;j++) now+=v[i][j],ans=max(ans,now);
        }
        else {//最大值一定出现在第一次循环
            if(d==0){
                for(int j=0;j<m;j++) now+=v[i][j],ans=max(ans,now);
            }
            else{
                for(int j=0;j<l;j++) now+=v[i][j],ans=max(ans,now);
            }
        }
    }
    cout<<ans<<endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

d.Sum of Divisors - SMUOJ

思路:由于查找每一个数的因数个数的过场是重复的,所以我们需要先预处理一下,代码类似晒法求素数的过程,这样只需要遍历一遍就可以找到所有数的因数个数,最后输出就好。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[10000010];
void solve(){
    int n;
    cin>>n;
    memset(a,0,sizeof a);
//参考筛法求素数的方法给每一个数查找因数个数
    for(int i=1;i<n;i++){
        int j;
        if(i==1 )j=i+1;
        else j=i;
        for(;i*j<=n;j++){
            if(i==j) a[i*j]++;
            else a[i*j]+=2;
        }
    }
    int sum=0;
    a[1]=1;
    for(int i=1;i<=n;i++) sum+=i*a[i];
    cout<<sum<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t -- ){
        solve();
    }
    return 0;
}

f.Rem of Sum is Num

思路:

区间和 用 前缀和处理

因此题目就变成求 有多少对 ( S [ i ] − S [ j ] ) % k = i − j 

即 :
S [ i ] − S [ j ] = k ∗ a + i − j(a 一个常数)
S [ i ] − i − ( s [ j ] − j ) = k ∗ a 
( s [ i ] − i ) % k = ( s [ j ] − j ) % k

因此我们可以先预处理除一个 长度为m i n ( k − 1 , n ) 、的区间
然后我们直接计算即可

题解:

#include <bits/stdc++.h>
using namespace std;
#define int  long long
#define ll long long
#define endl '\n'
const int N  = 2e5+10;
int x,f[N];
map<int,int> mp;

void solve()
{
    int n,k;cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>f[i];
        f[i] += f[i-1];
    }
    for(int i=1;i<=n;i++)
    f[i] = (f[i] - i)%k;

    int pos = min(n,k-1);
    ll sum = 0;

    for(int i= 0 ;i<=pos;i++)
    {
        sum+=mp[f[i]];
        mp[f[i]] ++;
    }
    for(int i=pos+1;i<=n;i++)
    {
        mp[f[i-k]] --;
        sum+=mp[f[i]];
        mp[f[i]]++;
    }
    cout<<sum<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    solve();
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值