比赛链接:第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛
A:斐波那契变形
规律:当前项 = 前面所有项之和 + 1,其实打表以后会发现是2^N,懒得改代码了直接交了。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 35;
long long a[MAXN];
int main()
{
a[0] = 0; a[1] = 1;
for (int i = 2; i < MAXN; i++)
{
for (int j = 0; j < i; j++)
{
a[i] += a[j];
}
a[i] += 1;
}
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
printf("%lld\n", a[n]);
}
return 0;
}
/*
1
1
*/
C:数学推导 + 中位数性质
思路:感觉这道题应该改编自UVA ~ 11300。大家可以先看下这道题:UVA ~ 11300 ~ Spreading the Wealth。
交换的金币数其实就是花费的时间。这个题分了互不影响几个圈,1 -> 1+(k+1) ->1+2(k+1) -> 1+3(k+1)...,直到出现循环。
加(k+1)的过程中这个值会超过N,要取余。每个圈按UVA~11300那道题处理,求一个最优值出来,累加就是答案。
注意要开long long。还有k=n和n-1的时候是无法传递金币的,所以这个情况要特判。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int n, k;
long long arr[MAXN], A[MAXN], C[MAXN], sum;
bool vis[MAXN];
long long solve(int n, int M)
{
C[0] = 0;
for (int i = 1; i < n; i++) C[i] = C[i - 1] + A[i] - M;
sort(C, C + n);
long long x1 = C[n/2], ans = 0;
for (int i = 0; i < n; i++) ans += abs(x1 - C[i]);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
while (cin >> n >> k)
{
memset(vis, 0, sizeof(vis));
sum = 0;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
sum += arr[i];
}
bool flag = true;
if (k == n || k == n-1)
{
for (int i = 0; i < n; i++)
{
if (arr[i] != sum / n) flag = false;
}
if (flag) printf("0\n");
else printf("gg\n");
continue;
}
long long ans = 0, cnt;
for (int i = 0; i < n; i++)
{
if (!vis[i])
{
cnt = 1; sum = 0;
for (int j = i; !vis[j]; j = (j + k + 1) % n)
{
vis[j] = true;
A[cnt++] = arr[j];
sum += arr[j];
}
if (sum % (cnt - 1)) { flag = false; break; }
ans += solve(cnt - 1, sum / (cnt - 1));
}
}
if (flag) printf("%lld\n", ans);
else printf("gg\n");
}
return 0;
}
/*
5 0
2 3 1 5 4
*/
D:最长回文子序列
思路:方法①原串与其反转串做LCS。方法②直接DP。
①原串与其反转串做LCS:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1300;
int dp[MAXN][MAXN];
int LCS(string a, string b)
{
int len1 = a.size(), len2 = b.size();
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= len1; i++)
{
for (int j = 1; j <= len2; j++)
{
if (a[i - 1] == b[j - 1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return dp[len1][len2];
}
int main()
{
ios::sync_with_stdio(false);
string str, t;
while (cin >> str)
{
for (int i = 0; i < str.size(); i++) str[i] = tolower(str[i]);
t = str; reverse(t.begin(), t.end());
cout << t.size() - LCS(str, t) << endl;
}
return 0;
}
/*
google
aBc,bAd
*/
②DP:(最长回文子序列好像叫LPS)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1300;
int dp[MAXN][MAXN];
int LPS(string str)//最长回文子序列
{
int len = str.size();
memset(dp, 0, sizeof(dp));
for (int i = len - 1; i >= 0; i--)
{
dp[i][i] = 1;
for (int j = i+1; j < len; j++)
{
if (str[i] == str[j])
dp[i][j] = dp[i+1][j-1]+2;
else
dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
}
}
return dp[0][len - 1];
}
int main()
{
ios::sync_with_stdio(false);
string str;
while (cin >> str)
{
for (int i = 0; i < str.size(); i++) str[i] = tolower(str[i]);
cout << str.size() - LPS(str) << endl;
}
return 0;
}
/*
google
aBc,bAd
*/
E:思维+map
思路:我们如果直接去枚举三个点,会超时。所以我们枚举这个转折点,然后判断有没有两个点到他的距离相等。怎么判断呢?我们可以用map<double,int>保存到当前转折点距离为d的点有几个,对于每个转折点扫一遍所有点就行了。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n;
pair<int, int> a[MAXN];
double dis(int i, int j)
{
return sqrt(pow(a[i].first - a[j].first, 2) + pow(a[i].second - a[j].second, 2) );
}
int main()
{
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--)
{
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i].first >> a[i].second;
int ans = 0;
for (int i = 0; i < n; i++)
{
map<double, int> M;
for (int j = 0; j < n; j++)
{
if (i == j) continue;
double t = dis(i, j);
if (!M.count(t)) M[t] = 1;
else
{
M[t]++;
ans += M[t];
}
}
}
if (ans == 0) cout << "WA" << endl;
else cout << ans << endl;
}
return 0;
}
/*
2
2
1 0
0 1
3
1 0
0 1
0 0
*/
F:数学推导+约数个数定理
思路:原式同分得nx+ny=xy,化为 -nx-ny+xy=0=,两边同时加n^2得 n^2-nx-ny+xy=n^2 =》 (n-x)(n-y)=n^2,所以该问题就变为求n^2的因子个数,所以直接上约数个数定理即可,不会的小朋友点这里点击打开链接
真是太厉害了,谁知道大神们都是怎么想到的呢?感觉到被智商压制,,,
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
long long n;
long long get_num(long long n)
{
long long cnt = 0, i = 2, ans = 1;
while (n != 1)
{
while (n%i == 0)
{
n /= i;
cnt++;
}
if (cnt != 0)ans *= (cnt + 1);
i++; cnt = 0;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--)
{
cin >> n;
cout << (get_num(n*n) + 1) / 2 << endl;
}
return 0;
}
/*
3
1
20180101
1000000000
*/
G:模拟矩阵旋转
思路:n*m矩阵右旋公式,【x,y】=》【y,n-i-1】,矩阵赋值可以直接利用swap。每次n,m都会互换,最后记得补'/0'。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 35;
int n, m;
char a[MAXN][MAXN], temp[MAXN][MAXN];
void Right(int n, int m)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j] == '-') temp[j][n - i - 1] = '|';
else if(a[i][j] == '|') temp[j][n - i - 1] = '-';
else temp[j][n - i - 1] = a[i][j];
}
}
swap(a, temp);
}
int main()
{
int T; scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
getchar();
for (int i = 0; i < n; i++) scanf("%s", a[i]);
string op; cin >> op;
int cnt = 0;
for (int i = 0; i < op.size(); i++)
{
if (op[i] == 'L') cnt--;
else if (op[i] == 'R') cnt++;
}
cnt = (cnt + 4 * op.size()) % 4;
//cnt %= 4; cnt += 4; cnt %= 4;
for (int i = 0; i < cnt; i++)
{
Right(n, m);
swap(n, m);
}
printf("%d %d\n", n, m);
for (int i = 0; i < n; i++)
{
a[i][m] = '\0';
printf("%s\n", a[i]);
}
printf("\n");
}
return 0;
}
/*
2
2 3
+-+
|+|
LLRRR
3 2
-+
+|
-+
LLL
*/
I:填空题,直接输出"ac"
J:思维题
思路:因为每次要加n-1个数字,所以每次一定有最小值。
设step: 总操作步数,ans:最终序列的元素,min:序列里的最小值 ,n:序列长度,sum:原序列之和。
ans = min+step
ans*n = sum+(n-1)*step
两个未知数两个方程解方程即可。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int INF = 0x3f3f3f3f;
int main()
{
int T, n; scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
int MAX = 0, MIN = INF, sum = 0;
for (int i = 0; i < n; i++)
{
int t; scanf("%d", &t);
sum += t;
MAX = max(MAX, t);
MIN = min(MIN, t);
}
sum -= MIN * n;
printf("%d %d\n", sum, MIN + sum);
}
return 0;
}
/*
1
3
1 2 3
*/
K:模拟
思路:直接模拟,或者找规律。模拟的时候注意一下n=1的情况。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n;
string str, ans[MAXN];
int main()
{
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--)
{
cin >> n >> str;
if (n == 1) { cout << str << endl; continue; }
int len = str.size(), tot = 0, x = 1;
while (tot < len)
{
while (x < n && tot < len) ans[x++] += str[tot++];
//if (x == n && tot < len) ans[x--] += str[tot++];
while (x > 1 && tot < len) ans[x--] += str[tot++];
//if (x == 1 && tot < len) ans[x++] += str[tot++];
}
for (int i = 1; i <= n; i++)
{
cout << ans[i];
ans[i].clear();
}
cout << endl;
}
return 0;
}
/*
100
3
ABABCADCE
1
ABABCADCE
*/
L:取log || 快速幂取模 || 分解质因数 || 放缩
取log:log(x^a)=log(y^b) =》a*log(x) = b*log(y),注意精度选取就好了。
#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
int x, a, y, b;
int main()
{
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--)
{
cin >> x >> a >> y >> b;
if (abs(a*log(x) - b*log(y)) <= eps) printf("Yes\n");
else printf("No\n");
}
return 0;
}
/*
4
2 20 4 10
20 20 20 20
20 21 21 20
32768 32768 1048576 24576
*/
快速幂取模:进行快速幂取模,试几个大点的质数就能过。 感觉这个有点玄学
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
long long x, a, y, b;
long long Pow(long long a, long long n)
{
if (n == 0) return 1;
long long res = Pow(a * a % mod, n / 2);
if (n&1) res = res * a % mod;
return res;
}
int main()
{
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--)
{
cin >> x >> a >> y >> b;
if (Pow(x,a) == Pow(y,b)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
/*
4
2 20 4 10
20 20 20 20
20 21 21 20
32768 32768 1048576 24576
*/
分解质因数:不想写了。。。
放缩:一个学妹教我的。稍微有一点麻烦就不讲了
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T; scanf("%d", &T);
while (T--)
{
int x, a, y, b;
bool flag = false;
scanf("%d%d%d%d", &x, &a, &y, &b);
for (int i = 0; i < 100; i++)
{
if (x == y && a == b) { flag = true; break; }
if (a < b) { swap(a, b); swap(x, y); }
a = a - b;
if (y % x) break;
y = y / x;
}
if (flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}
/*
4
2 20 4 10
20 20 20 20
20 21 21 20
32768 32768 1048576 24576
*/
本文解析了第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛的多个题目,包括斐波那契变形、数学推导、最长回文子序列等问题,并提供了详细的代码实现。
412

被折叠的 条评论
为什么被折叠?



