csust2020新生赛题解

1.会长的数字
签到题,只要找输入的数字中有无某一位数字除以2等于0。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
char s[maxn];
int main(){
    
    
   scanf("%s",s+1);
   int d=strlen(s+1),flag=0;
   for(int i=1;i<=d;i++){
    
    
        int num=s[i]-'0';
        if(num%2==0){
    
    
            flag=1;
        }
   }
   printf(flag?"YES\n":"NO\n");
   return 0;
}

2.这是你的气球
签到题,因为要求x,y是正整数,所以x可以取的值是1~n-1,所以一共有n-1个二元组。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
int main()
{
    
    
    int n;
    cin>>n;
    cout<<(n-1)<<endl;
}

3.二进制
思维题,对数组从左往右遍历,cnt数组表示当前前缀的1的数量,ans表示答案,res表示已经遇到的1对后面1的贡献,如果遇到1,则cnt++,ans+=res,即表示前面的所有的1对现在的1的贡献加到答案里面,还要注意每一步res都要更新成res+cnt,最后注意取模的问题就行。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
int a[MAXN];
int main()
{
    
    
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>a[i];
    }
    int ans=0;
    int res=0;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
    
    
        res=(res+cnt)%mod;
        if(a[i]==1)
        {
    
    
            cnt++;
            ans=(ans+res)%mod;
        }
    }
    cout<<ans<<endl;
}

4.聪明的qc

分析子问题 2 3 1,这肯定是第一个拿第一堆的人(First)获胜,再来分析 5 2 2 2,根据前面分析的2 3 1,2 2 2 
同理也是当前先拿的人获胜,所以第一个拿第一堆的人可以计划他也是第一个拿第二堆的人,那么它可以先拿到第一堆石头的a[1]-1个,
这样他也是第一个拿第二堆的,由此分析,谁先拿到第一个不为1的石头,就谁获胜。
所以记录一下前缀1的最长位置即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=2e6+5;
int a[MAXN];
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--) {
    
    
    	int n;
        scanf("%d",&n);
        for(int i = 0; i < n; i++) {
    
    
            scanf("%d",&a[i]);
        }
        int k = 0;
        while(k < n && a[k] == 1) {
    
    
            k++;
        }
        cout << ((k == n) ^ (k % 2==1) ? "Second" : "First") << '\n';
    }
    
}

5.约会大作战
利用二分的思想,找出最优的天数.
假定出一个天数,然后从后往前遍历.
如果第一次遇到某种精灵,那么就让你所有要准备的天数减去这个精灵要考的天数,同时把这种课标记掉.
如果你遍历到某一天是0或者是这一门已经被标记掉了,那么就让所有剩余的天数减一,因为你这一天拿来复习了.
当然,如果你剩余的天数小于你总的需要复习的天数,那么就返回错误.
遍历完成,看一下剩余的天数是否为0,如果为0就返回正确,否则返回错误.

思路:二分每一天,看这天是不是能考完。

判断能考完的方法:从这天向前遍历,若这天有精灵且这个精灵还没约会,我们就跟这个精灵约会,若这天没有精灵,我们就休息。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
int n,m;
int d[MAXN];
int a[MAXN];
int vis[MAXN];
int num[MAXN];
bool check(int mid)
{
    
    
    int sum=0;
    int cnt=0;
    for(int i=1;i<=m;i++) vis[i]=0;
    for(int i=1;i<=mid;i++) num[i]=0; 
    for(int i=mid;i>=1;i--)
    {
    
    
        if(d[i]==0) continue;
        else if(vis[d[i]]==0) {
    
    num[i]=1;vis[d[i]]=1;}
    }
    for(int i=1;i<=mid;i++)
    {
    
    
        if(num[i]==0) sum++;
        else
        {
    
    
            if(sum>=a[d[i]]) {
    
    sum-=a[d[i]];cnt++;}
            else return 0;
        }
    }
    if(cnt==m) return 1;
    else return 0; 
}
int main()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d",&d[i]);
    }
    for(int i=1;i<=m;i++)
    {
    
    
        scanf("%d",&a[i]);
    }
    int l=1,r=n;
    int ans=-1;
    while(l<=r)
    {
    
    
        int mid=(l+r)>>1;
        //cout<<mid<<endl;
        if(check(mid))
        {
    
    
            ans=mid;
            r=mid-1;
        }
        else
        {
    
    
            l=mid+1;
        }
    }
    if(ans==-1) printf("impossible\n");
    else printf("%d\n",ans);
}

6.狼抓兔子
bfs裸题,因为兔子最终能跑到四个点,每个点都有可能,所以直接bfs计算狼到这四个点的最短距离,取个最小值,最后还得判断狼能不能到达这四个点。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
char s[1005][1005];
int vis[1005][1005];
int ans[1005][1005];
int n,m;
struct node
{
    
    
    int x,y;
    int val;
};
int tx[4]={
    
    1,-1,0,0};
int ty[4]={
    
    0,0,1,-1};
bool ok(int x,int y)
{
    
    
    if(x>=1&&x<=n&&y>=1&&y<=m) return true;
    else return false;
}
void bfs(int x2,int y2)
{
    
    
    queue<node>q;
    node now;
    now.x=x2;now.y=y2;
    now.val=0;
    vis[x2][y2]=1;
    ans[x2][y2]=0;
    q.push(now);
    while(!q.empty())
    {
    
    
        now=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
    
    
            int nx=now.x+tx[i];
            int ny=now.y+ty[i];
            //cout<<nx<<" "<<ny<<endl;
            if(ok(nx,ny)&&s[nx][ny]!='#'&&vis[nx][ny]==0)
            {
    
    
                //cout<<nx<<" "<<ny<<endl;
                node pre;
                pre.x=nx;
                pre.y=ny;
                pre.val=now.val+1;
                ans[nx][ny]=pre.val;
                vis[nx][ny]=1;
                q.push(pre);
            }
        }
    }
}
int main()
{
    
    
    int x1,y1,x2,y2;
    scanf("%d%d",&n,&m);
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%s",s[i]+1);
    }
    memset(ans,-1,sizeof ans);
    bfs(x2,y2);
    int res=1e9;
    if(ans[1][y1]!=-1) res=min(res,ans[1][y1]);
    if(ans[n][y1]!=-1) res=min(res,ans[n][y1]);
    if(ans[x1][1]!=-1) res=min(res,ans[x1][1]);
    if(ans[x1][m]!=-1) res=min(res,ans[x1][m]);
    if(res==1e9) 
    {
    
    
        printf("NO\n");
    }
    else
    {
    
    
        printf("YES\n");
        printf("%d\n",res);
    }
}

7.狂风绝息斩
简单动态规划题,枚举每个点,这个点要么是从前一个点转移过来,要么是从前前点转移过来,所以可写出动态规划方程
dp[i]=dp[i-1]+dp[i-2]。
注意要初始化1 和2这两个点
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e3+5,inf=0x3f3f3f3f,mod=2017;
const double eps=1e-10;
int n,m;
ll dp[maxn];
int main(){
    
    
    scanf("%d",&n);
    dp[0]=1;
    for(int i=1;i<=n;i++){
    
    
        dp[i]=dp[i-1]+dp[i-2];
    }
    cout<<dp[n]<<endl;
    return 0;
}

8.吸金达人
一道很强的思维题,首先就是如果可以使得所有的点变成一个点,那么必然存在只让一个点就可以吸引完其它所有的点(这里仔细想想,因为我们无法改变点与点之间的距离)所以按这样来看我们的最小操作次数就是1 ,而如果不存在则说明不可行,我们输出− 1 即可。所以实际上我们可以暴力枚举一下,是否存在一个点可行。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
int x[MAXN];
int y[MAXN];
int main()
{
    
    
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,k;
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
    
    
            cin>>x[i]>>y[i];
        }
        if(n==1||n==0)
        {
    
    
            cout<<"angry"<<endl;
            continue;
        }
        int flag=0;
        for(int i=1;i<=n;i++)
        {
    
    
            int cnt=0;
            for(int j=1;j<=n;j++)
            {
    
    
                if(i==j) continue;
                if(abs(x[i]-x[j])+abs(y[i]-y[j])<=k)
                {
    
    
                    cnt++;
                }
            }
            if(cnt==n-1)
            {
    
    
                flag=1;
                break;
            }
        }
        if(flag)
        {
    
    
            printf("1\n");
        }
        else
        {
    
    
            printf("-1\n");
        }
    }
}

9.潇洒哥VS喜羊羊
我们可以求出数组元素的和,如果和为奇数,每次减少2永远会剩下,所以我们要寻找的是和为偶数的片段

如果满足偶数和,那么最大值如果不能被抵消掉也是不可以的,比如这串数:1,2,3,1000,这串数的和为偶数,但是是不可能全变成0的。

所以我们需要判断最大数能否被抵消掉,如果最大数的2倍比和要大,意味着无法抵消掉最大数

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
//#define int long long
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int n,a[maxn],ma;
ll sum=0;
bool flag=0;
signed main(){
    
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    
    
        scanf("%d",&a[i]);
        sum+=a[i];
        ma=max(ma,a[i]);
    }
    if(ma<=sum/2&&sum%2==0){
    
    
        flag=1;
    }
    string a,b;
    cin>>a>>b;
    if(a==b){
    
    
        cout<<"huagequanquanzuzhouni"<<endl;
    }else{
    
    
        if(flag&&a=="YES"||(!flag&&a=="NO")){
    
    
            cout<<"huagequanquanzuzhouni"<<endl;
        }else{
    
    
            cout<<"huagequanquanzhufuni"<<endl;
        }
    }
    return 0;
}

10.就算女装也在所不辞
直接二分最长练习时间,因为是把连续的合为一组,所以贪心的去想,每组的时长肯定是尽可能的靠近二分的时间,这样可以使得组数最少,按顺序遍历,sum表示当前组的练习时长,cnt表示组数,如果sum+当前时长小于等于二分的答案,说明当前节练习可以加入到第cnt组,否则,cnt++,即尽量充分的填满时间,如果遍历完后的组数<=k,则合法,r=mid-1,否则 r=mid+1。注意,如果存在某节练习时长大于二分的时间,那么直接是不合法的。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;
ll a[maxn];
int n,k;
bool check(ll mid)
{
    
    
    int res=0;
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
    
    
        if(a[i]>mid) return 0;
        if(a[i]+sum<=mid)
        {
    
    
            sum+=a[i];
        }
        else
        {
    
    
            res++;
            sum=a[i];
        }
    }
    res++;
    if(res<=k)
    {
    
    
        return 1;
    }
    else return 0;
}
int main()
{
    
    
    cin>>n>>k;
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>a[i];
        sum+=a[i];
    }
    ll l=1,r=sum;
    ll ans=-1;
    while(l<=r)
    {
    
    
        ll mid=(l+r)/2;
        if(check(mid))
        {
    
    
            r=mid-1;
            ans=mid;
        }
        else
        {
    
    
            l=mid+1;
        }
    }
    printf("%lld\n",ans);
}

11.会长大逃亡
动态规划,设dp[i][j]表示传送j次到达i点的最小时间花费。
则状态转移方程为:
dp[i][j]=min(dp[i-1][j]+t,dp[pre][j-1])
pre表示某个能传送到 i 点的点。注意要对dp初始化为-1,
并且dp[1][0]=0。
此处附上标准版和简洁版代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
int n,k,t;
int p[MAXN];
int dp[MAXN][40];
int main()
{
    
    
    scanf("%d%d%d",&n,&k,&t);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d",&p[i]);
    }
    memset(dp,-1,sizeof dp);
    dp[1][0]=0;
    if(p[1])
    {
    
    
        for(int j=0;j<=k-1;j++)
        {
    
    
            if(dp[1][j]!=-1)
            {
    
    
                if(dp[p[1]][j+1]==-1) dp[p[1]][j+1]=dp[1][j];
                else dp[p[1]][j+1]=min(dp[p[1]][j+1],dp[1][j]);
            }
        }
    } 
    for(int i=2;i<=n;i++)
    {
    
    
        for(int j=0;j<=k;j++)
        {
    
    
            if(dp[i-1][j]!=-1)
            {
    
    
                if(dp[i][j]==-1) dp[i][j]=dp[i-1][j]+t;
                else dp[i][j]=min(dp[i][j],dp[i-1][j]+t);
            }
        }
        if(p[i])
        {
    
    
            for(int j=0;j<=k-1;j++)
            {
    
    
                if(dp[i][j]!=-1)
                {
    
    
                    if(dp[p[i]][j+1]==-1) dp[p[i]][j+1]=dp[i][j];
                    else dp[p[i]][j+1]=min(dp[p[i]][j+1],dp[i][j]);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
    
    
        int ans=1e9+7;
        for(int j=0;j<=k;j++)
        {
    
    
            if(dp[i][j]!=-1)
            {
    
    
                ans=min(ans,dp[i][j]);
            }
        }
        printf("%d ",ans);
    }
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
int n,k,t,q;
int dp[maxn][35],ans[maxn];
vector<int> vec[maxn];
int main(){
    
    
    scanf("%d%d%d",&n,&k,&t);
    memset(dp,0x3f3f3f3f,sizeof(dp));
    memset(ans,0x3f3f3f3f,sizeof(ans));
    for(int i = 1,x; i <= n; i ++){
    
    
        scanf("%d",&x);
        vec[x].push_back(i);
    }
    dp[1][k] = 0;
    for(int i = 2; i <= n; i ++){
    
    
        for(int j = 0; j <= k; j ++){
    
    
            for(auto pre: vec[i]){
    
    
                dp[i][j] = min(dp[i][j],dp[pre][j + 1]);
            }
            dp[i][j] = min(dp[i][j],dp[i - 1][j] + t);
        }
    }
    for(int i = 1; i <= n; i ++){
    
    
        ans[i] = dp[i][0];
        for(int j = 0; j <= k; j ++){
    
    
            ans[i] = min(ans[i] , dp[i][j]);
        }
      printf("%d ",ans[i]);
    }
    return 0;
}

12.你真的会判断素数吗?
虽然测试数据很大,但能满足题意的素数很少,并且不大,所以直接dfs枚举每一位的数字,过程中可以暴力判断素数,ac代码用的是vector存的答案,不会vector的可以用数组存答案,效果是一样的。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e5+5;
const int mod=1e9+7;
ll n;
int ans;
std::vector<ll> v;
bool is_prime(ll x)
{
    
    
    if(x==1||x==0) return 0;
    int k=sqrt(x);
    for(int i=2;i<=k;i++)
    {
    
    
        if(x%i==0) return 0;
    }
    return 1;
}
void dfs(ll sum)
{
    
    
    if(is_prime(sum)&&sum<=n) {
    
    ans++;v.push_back(sum);}
    else return;
    dfs(sum*10+1);
    dfs(sum*10+3);
    dfs(sum*10+7);
    dfs(sum*10+9);
}
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        v.clear();
        ans=0;
        scanf("%lld",&n);
        if(2<=n) dfs(2);
        if(3<=n) dfs(3);
        if(5<=n) dfs(5);
        if(7<=n) dfs(7);
        if(ans==0) 
        {
    
    
            printf("0\n");
            printf("\n");
        }
        else
        {
    
    
            printf("%d\n",ans);
            sort(v.begin(),v.end());
            for(int i=0;i<v.size();i++)
            {
    
    
                if(i!=v.size()-1)printf("%lld ",v[i]);
                else printf("%lld",v[i]);
            }
            printf("\n");
        }
    }
}

13.水题大赛
单纯的模拟题,按照题意模拟一下就行了,注意下一些细节。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;

int n,m,w[12],a[100012][5][10];

int main(){
    
    
	scanf("%d%d",&n,&m);
	int cnt2=1,cnt3=1;
	w[1]=50,w[2]=40,w[3]=30,w[4]=20,w[5]=10;
	for (int i=1;i<=m;i++)
	{
    
    
	  int s,b,c,d;
	  scanf("%d L%d-%d %d",&s,&b,&c,&d);
	  a[s][b][c]=max(a[s][b][c],d);
	  if (b==2&&d==25&&cnt2<=5&&a[s][2][0]==0)
	    a[s][2][0]+=w[cnt2],cnt2++;
	  if (b==3&&d==30&&cnt3<=5&&a[s][3][0]==0)
	    a[s][3][0]+=w[cnt3],cnt3++;
	}
	for (int i=1;i<=n;i++)
	{
    
    
	  int a1=0,a2=0,a3=0;
	  for (int j=1;j<=8;j++)
	    a1+=a[i][1][j],a2+=a[i][2][j],a3+=a[i][3][j];
	  if (a1<80)
	    printf("%d\n",a1);
	  if (a1>=80&&a2<40)
	    printf("%d\n",a1+a2+a[i][2][0]);
	  if (a1>=80&&a2>=40)
	    printf("%d\n",a1+a2+a[i][2][0]+a3+a[i][3][0]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45755679/article/details/111231852