2020年广东工业大学第十届文远知行杯新生程序设计竞赛

比赛链接

A. 肥猪的钢琴床

题意:

将 01字符串转化为最多只有一段连续1的字符串,求最小删除字符数

思路:

转化后的字符串可化为 \(0 ⋯ 0 + 1 ⋯ 1 + 0 ⋯ 0\)三段,每一段的长度都可能为 0

\(dp[i][0/1/2]\)为第 \(i\)个字符位于 \(1 / 2 / 3\) 段需要删除的最小字符(第 \(i\)个字符可能要被删除)

状态转移方程很简单,详见代码

#include<bits/stdc++.h>
using namespace std; 
const int N=1e6+5;
char s[N];
int n,dp[N][3];
int main() {
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++) {
        if(s[i]=='1') {
            dp[i][0]=dp[i-1][0]+1;//把1删了 
            dp[i][1]=min(dp[i-1][0],dp[i-1][1]);//第二段的1,可能在第二段首,也可能不在 
            dp[i][2]=min(dp[i-1][1],dp[i-1][2])+1;//第三段的0,可能在出现在第三段首,也可能不在,但一定被删 
        }
        else{
            dp[i][0]=dp[i-1][0];
            dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;//第二段的0,可能在出现在第二段首,也可能不在,但一定被删 
            dp[i][2]=min(dp[i-1][1],dp[i-1][2]);//第三段的0,可能在出现在第三段首,也可能不在
        }
    }
    //最后一个字符一定处于这三种状态中,挑出最小的即可 
    printf("%d\n",min({dp[n][0],dp[n][1],dp[n][2]}));
    return 0;
}

也可写为:

scanf("%s",s+1);
for(int i=1;i<=n;i++){
    dp[i][0] = dp[i-1][0] + (s[i]-'0');
    dp[i][1] = min(dp[i-1][0] + ('1'-s[i]), dp[i-1][1] + ('1'-s[i]));
	dp[i][2] = min(dp[i-1][1] + (s[i]-'0'), dp[i-1][2] + (s[i]-'0'));
}
cout<<min(dp[n][0], min(dp[n][1], dp[n][2]));

B. 拯救小a

签到

C. 母牛的俄罗斯轮盘赌

思路:

简单博弈:

  • 打表到10发现周期为5重复(博弈有时要耐心打表)
  • 显然能开出第n-1枪的是胜者,易证得开出第k枪的玩家一定能开出第k+5枪,算出n<=5的答案即可

D. 中学数学题

思路:

数论:
原题\(\Leftrightarrow\)找到阶乘中能除尽p的因子\(\Leftrightarrow\)再求这些因子能除尽p的次数总和

#include <stdio.h>
int main(){
    int t;
    scanf("%d",&t);
    int n,p;
    for(int i = 0;i < t;i++){
		scanf("%d%d",&n,&p);
		int count = 0;
		for(int j = p;j <= n;j += p){ //找出所有p的倍数:1p,2p,3p...
			int k = j;
			while(k % p == 0){//计算p的倍数中包含p个数,即要除以几次才能余数不为0,即0的个数
				count++;
				k /= p;
			}
		}
		printf("%d\n",count);
    }
    return 0;
}

E. 枚举求和

思路: 有多少个\(i\)\(j\)都是\(k\)的倍数,于是,直接输出\((n/k)*(m/k)\).

F. 合并石子

思路:

\[消耗体力总和=合并时的所有情况数*\sum ^{n-1}_{i=1}第i次合并时任意选取两堆的期望和 \]

在这里插入图片描述

#include <bits/stdc++.h>
#define M 1000000007
using namespace std;
typedef long long ll;
ll ksm(ll a,ll p){
    ll res=1;
    while(p){
		if(p&1){res=res*a%M;}
		a=a*a%M;p>>=1;
	}
	return res;
}
int i;
ll n,res,tmp;
int main(){
    scanf("%d",&n);
    for(i=2;i<=n;i++)
        res+=ksm(i,M-2)*n%M;//对i求模M的逆元     
    for(i=1;i<=n-1;i++)
        res=res*i%M;   
    printf("%lld",res*2%M);
}

G. 排解忧伤

思路:

显然,无论以任何顺序入场,怒气值之和都不会改变,你只要以你喜欢的顺序入场计算就好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x){
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
const int N=1e5+5;
ll n,m,s=1,ans=0,a[N];
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++) read(a[i]);
    sort(a+1,a+1+m);
    for(int i=1;i<=n;i++){
    //刚开始a[s]==i时就坐下,之后可能就a[s]<i时坐下 
        if(a[s]<=i){
            ans+=i-a[s];
            s++;
        }
        if(s==m+1) break;
    }
    if(s!=m+1) puts("-1");
    else cout<<ans;
    return 0;
}

H. 台灯

待补QAQ

I. 历史

签到

J. 母牛烃

思路:

因为答案的多解性,判题机应该是动态判题,也就是每个人答案其实可以不同,给定的数据也可能不同。

所以考虑怎么做到让任意碳-碳键 (别被双键坑了,这里默认所有键都是碳-碳双键) 上的能量都不相同:可以想到的是我们分别给1-n的碳原子随机赋值1~n内不重复的数字,这样也就出现了一种思路(此题应该还有很多种解法,太菜了只会这种):

贪心推结论: 从开始进行k的赋值是分别将n,1,n-1,2,n-3,3 ……赋值给主链上第i个碳原子以及它所对应的支链碳原子,这样过后每一个碳原子与相连碳原子的势力值的差值也就不同(从1~n的n个差值,刚好各不相同,自己可以举例验证)

#include<bits/stdc++.h>
int n,m,i,j,k,b[10010],a[10010];
int main(){
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
		scanf("%d",&b[i]);//读入主链上碳原子的编号
	int f[2];f[0]=1;f[1]=n;//两头开始 
	int s=0;//s不是0就是1 ; 0表示左边,1表示右边 
	int ans;
	for(i=1;i<=m;i++){
		a[b[i]]=f[s];
		f[s]+=s?-1:1;//s是1则f[1]向左移动(--),反之f[0]向右移动(++) 
		scanf("%d",&k);
		if(k>0){
			for(j=1;j<=k;j++){
				scanf("%d",&ans);//读入直接相连的碳原子的编号
				a[ans]=f[1-s];
				f[1-s]+=s?1:-1;
			}
		}
		s=1-s;
	}
	for(i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]);
	return 0;
} 

K. 很基础的模拟题

:复习vector啦

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<bits/stdc++.h>
#define LL long long 
using namespace std;
template<class T>inline void read(T &x){
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
int main(){
	vector<int> v;
	int n,q,t;
	cin>>n>>q;
	int q1;
	int c1,c2;
	for(int i=0;i<n;i++)read(t),v.push_back(t);
	while(q--){
		cin>>q1;
		if(q1==1){
			cin>>c1;
			v.erase(v.begin()+c1-1);
			for(auto it:v)
				cout<<it<<" ";			
			cout<<endl;
		}
		else if(q1==2){
			cin>>c1>>c2;
			v.insert(v.begin()+c1-1,c2);
			for(auto it:v)
				cout<<it<<" ";			
			cout<<endl;
		}
		else{
			cin>>c1;
			c1--;
			int k=*(v.begin()+c1),cnt=1;
			vector<int>::iterator it;
			int sum=k;
			for(it=v.begin()+c1+1;it!=v.end();it++){  
			    if(*it==k)
			    	sum+=k,cnt++;				
				else break;
			} 
			for(int i=0;i<cnt;i++)
				v.erase(v.begin()+c1);			
			v.insert(v.begin()+c1,sum);
			for(auto it:v)
				cout<<it<<" ";			
			cout<<endl;
		}
	} 
    return 0;
}

L. 母牛上柱

思路:

签到,注意angle=fabs(a-b); angle=min(angle,360-angle),几何关系WA了一发,血亏

posted @ 2021-01-10 00:27  chenshunpeng  阅读(110)  评论(0)    收藏  举报