GDUT初赛题解

这次比赛,看到了自己跟大家的差距,所谓的大神是从一点一滴练起的。不是说钻研得多高深,就多牛;而是所有的题干细节处理到位,所有能做的题1A,向bin神学习吧,同志们!一起加油!

说明:这个题解,有我自己的代码,也有bin神的,axp巨巨的,Tonny巨巨,还有好多帮助过我的人,希望群巨多多参与题解的建设,方便自己做总结,也方便群巨学习。


话不多说。从每一题开始(题意全部略去)

第一天

A.模拟。对3种情况,分别进行处理。容易出现的错误有:注意当队伍中已经没人的时候请忽略第2种事件,每组数据新开始的时候队伍中人数都为0!另外,我一开始实现的代码是用queue写的,不知道为什么超时了。。。估计是迭代器比较慢。AC代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
#define For1(i,a,b) for (i=a;i

细节:注意head


B.按照题意,对输入的数字进行转换。我的代码很挫,改了又改最后对的。对于n=1000的这种小数据,告诉大家一个1A的方法,用freopen形成一个1到1000的测试数据,看看答案是不是有规律连续的即可。

我的代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
#define For1(i,a,b) for (i=a;i=27&&n<=26*27){
		for(j=1;j<=26;j++)
			for(k=1;k<=26;k++){
				if (j*26+k==n){
					printf("%c",j+'A'-1);
					printf("%c",k+'A'-1);
					puts("");
					return;
				}
			}
	}
	printf("A");
	for(j=1;j<=26;j++)
		for(k=1;k<=26;k++){
			if (j*26+k==n-26*26){
				printf("%c",j+'A'-1);
				printf("%c",k+'A'-1);
				puts("");
				return;
			}
		}
}
int main(){
	int t;
	int n;
	int ans[500];
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		Print(n);
	}
	return 0;
}

上上bin神的代码,每道题都可以学学不同的思路,有时候有了题解,不要懒,自己实现实现

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
	int n;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		if(n <= 26){
			printf("%c\n",(char)('A'+n-1));
		}
		else if(n <= 26+26*26){
			n -= 27;
			printf("%c%c\n",(char)('A'+n/26),(char)('A'+n%26));
		}
		else {
			n -= 26+26*26+1;
			printf("%c%c%c\n",(char)('A'+n/26/26),(char)('A'+(n/26)%26),(char)('A'+n%26));
		}
	}
    return 0;
}


又有一个巨巨提供的代码,觉得挺好的,供大家学习string的细节处理:

#include 
#include 
int main()
{
    int N;scanf("%d",&N);
    while(N--)
    {
        int n,cnt=0;
        char s[16];
        scanf("%d",&n);
        while(n)
        {
            int m=n%26;
            if(!m)m=26;
            s[cnt++]=m+64;
            n=(n-m)/26;
        }
        for(int i=cnt;i;--i)
            putchar(s[i-1]);
        puts("");
    }
    return 0; 
}


C.这道题不需要题解的吧。。给大家提供个bin神快的诀窍。

sort(a,a+n)代表对a数组中的a[0]到a[n]从小到大排序

reverse(a,a+n)代表对a数组中所有元素反序存储。之后的。大家懂


D.这个题是比较好的一道题。有多种做法。

先说说思路。

1.bin神思路。dp[i][0]代表共i位数字,最后1位为0的不含有11的数目,dp[i][1]代表共i位数字,最后1位为1的不含有11的数目,这样,答案就是2^n-dp[i][0]-dp[i][1]。递推过程很好想。代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int MOD = 1e9+7;
int dp[1000010][2];
void Add(int &a,int b){
	a += b;
	if(a >= MOD)
		a -= MOD;
}
int two[1000010];

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    memset(dp,0,sizeof(dp));
	dp[1][0] = dp[1][1] = 1;
	two[1] = 2;
	for(int i = 2;i <= 1000000;i++){
		dp[i][0] = dp[i-1][1]+dp[i-1][0];
		if(dp[i][0] >= MOD)
			dp[i][0] -= MOD;
		dp[i][1] = dp[i-1][0];
		two[i] = 2LL*two[i-1]%MOD;
	}
	int T;
	int n;
	cin>>T;
	while(T--){
		scanf("%d",&n);
		int ans = two[n]-(dp[n][0]+dp[n][1])%MOD;
		ans = (ans%MOD+MOD)%MOD;
		printf("%d\n",ans);
	}
    return 0;
}

2.dfs处理所有小数据(或者手算打表)。发现ans[n]=2*ans[n-1]-f[n-1],其中f代表斐波那契数列,其中f[1]=f[2]=1。打表不贴代码,大家自己实现吧。

3.axp巨巨提供:光棍是递推,长度为n的有两种情况,110+长度为n-3不符合情况的,0或1加上长度为n-1符合要求的

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 1000100;
const int mod = 1000000007;
int arr[maxn];
int two[maxn];
int T,n;

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
	two[0]=1;
	for(int i=1;i>T;
	while(T--)
	{
		scanf("%d",&n);
		printf("%d\n",arr[n]);
	}
    return 0;
}


5.物理题。。大家注意,题中条件少,意味着需要自己找。判断要求为:炮弹45度出发打不中的话就肯定打不中了(高中物理)。就是求以v斜向上45度发射,求最大距离x与d的关系。x=v^2/g。分解成水平速度v0和垂直速度vy。大家都会的。细心就好


6.我大概懂了,axp巨巨教的。每次循环都改动字符串,就是第i位和第len-k+i相同所以就统计所有相隔len-k的字符,选出出现次数最多的,把这些字符都修改为这个字符,统计要修改的次数就是答案了。代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int ans;
const int maxn = 1100;
char ch[maxn];
int T,k;
int arr[26];
int be;
int l;

int f(int x)
{
	memset(arr,0,sizeof(arr));
	int re=0;
	int r=0;
	while(x>T;
	while(T--)
	{
		scanf("%s%d",ch,&k);
		l=strlen(ch);
		be=l-k;
		ans=0;
		for(int i=0;i

上面这题我一直没过是因为我用贪心思考的,判断的时候没有管到连续的修改值的问题。axp巨巨Hack我的数据是aaabbbccc 8。我的贪心代码比较渣,只关注了第i位和第i位匹配位和第len-i位的匹配位。没有想到链接的关系。Hack数据len=9,k=8,意思是连续的都相同,即为所有字符都一样。所以,贪心策略不知道实行多少次,没有贪心的正确性保证,只能用类似搜索的方法实现。


7.既然是颗树,既然是n=1000,dfs和bfs是不会有问题的。我的思路,用ans[i]记录,若等于0说明未访问过,若等于j说明走到i之前必须过j(由于是颗树),dfs时数目肯定不会大,因为每次扩展的节点是有限的。代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
#define For1(i,a,b) for (i=a;i

8.大大的水题。给个式子就好了。

num[1]=1;
num[2]=2;
for(i=3;i<=1000;i++)
     num[i]=num[i-1]+i-1;

小数据打表就好。



初赛的题解就到这里。谢谢bin神,axp巨巨,Tonny巨巨和群巨的帮助和支持。希望大家也能分享自己的AC和各种错误,一起提高。

Hint:比赛就是这样,还记得我初中数学老师说的,打不了满分就不要说题目简单。放到ACM也一样,这道题你不是1A就没有资格说它简单,这场比赛没有AK,有错误就不够完美,赛后题解只是补充学习,更多的是大家平时的细节注意,大家为着梦想加油!

你可能感兴趣的:(ACM题解)