第八屆“圖靈杯”NEUQ-ACM程式設計競賽個人賽
技術標籤:ACM--比賽補題
文章目錄
第八屆“圖靈杯”NEUQ-ACM程式設計競賽個人賽
A 切蛋糕
題意: 現在有一個蛋糕,需要分給k個人,每次操作可以將一個蛋糕分為2份,還可以選擇一些蛋糕打包為一份,最後需要打包出k份,使得每一份的蛋糕量為1/k,誤差不大於1e-10,全部操作需要在6000步內完成‘。k保證不大於2e10
題解: 直接將所有的蛋糕分為1/1e-10,這樣需要的運算元為2e11-1,也就是2047次,然後打包出k份,操作次數不超過2e10,總體不超過2047+1024次,小於6000次
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
int n, m, T;
int two[15];
void init()
{
two[0] = 1;
for (int i = 1; i < 13; i++)
{
two[i] = 2 * two[i - 1];
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
init();
cout << two[11] - 1 + n << endl;
int cnt = 0;
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j < two[i]; j++)
{
cout << 1 << " " << i << endl;
}
}
double ans = 1.0 / n
int num = ans / (1.0 / two[11]);
for (int i = 0; i < n; i++)
{
cout << 2 << " " << num;
for (int j = 0; j < num; j++)
cout << " " << 11;
cout << endl;
}
return 0;
}
B 小寶的幸運陣列
題意: 給出一個長度為n的陣列,要求找到一個區間使得區間和為k的倍數,如果有的話輸出最長的區間長度,否則輸出-1
題解: 記錄字首和出現的最早位置,然後相減即可,需要每次都模k,這樣保證區間和是k的倍數
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, r;
LL sum[N], a[N], k;
map<LL, int> mp;
int main() {
cin >> t;
while (t--) {
cin >> n >> k;
mp.clear();
int res = -1;
mp[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = (sum[i - 1] + a[i] % k) % k;
if(mp.count(sum[i])){
res = max(res, i - mp[sum[i]]);
}
else
mp[sum[i]] = i;
}
cout << res << endl;
}
return 0;
}
C 上進的凡凡
題意: 給出長度為n的陣列,求出其中不下降子陣列的數量
題解: 直接掃一遍,如果遇到長度為k的不下降子陣列,那麼答案應該加上1到k的累加和
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
LL n, m, T;
LL a[N];
LL jie[N+10];
void init(){
jie[0]=jie[1]=1;
for(int i=2;i<=N;i++){
jie[i]=jie[i-1]+i;
}
}
int main() {
cin>>n;
init();
for(int i=1;i<=n;i++){
cin>>a[i];
}
LL num=0;
LL ans=0;
for(int i=1;i<=n;i++){
if(a[i]>=a[i-1]) num++;
else{
ans+=jie[num];
num=1;
}
}
ans+=jie[num];
cout<<ans<<endl;
return 0;
}
D Seek the Joker I
題意: 一共n個數的堆,從上到下開始取,每次最少取1個,最多取k個,取到最後一個的為輸
先手贏輸出yo xi no forever!
後手贏輸出ma la se mi no.1!
題解: 巴什博弈裸題
程式碼:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, k;
int main(){
cin >> t;
while(t--){
cin >> n >> k;
if (n % (k + 1) == 1) cout << "ma la se mi no.1!" << endl;
else
cout << "yo xi no forever!" << endl;
}
return 0;
}
E Seek the Joker II
題意: 一個n個數的堆,每次可以從上面取任意個數,或者從下面取任意個數,或者同時從上面和下面取相同多個數,取到原來第x個的為輸。先手贏輸出yo xi no forever!。後手贏輸出ma la se mi no.1!
題解: 威佐夫博弈裸題
程式碼:
#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
int n1,n2,temp, n, x;
cin >> T;
while(T--) {
cin >> n >> x;
n1 = x - 1, n2 = n - n1 - 1;
if(n1>n2) swap(n1,n2);
temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);
if(temp==n1) cout<<"ma la se mi no.1!"<<endl;
else cout<<"yo xi no forever!"<<endl;
}
return 0;
}
F 成績查詢ing
題意: 給出n個人的學號、成績、性別、姓名。然後是m次查詢,如果輸入的是成績,則輸出全部的成績為這個成績的學生的姓名(按字典序)。如果查詢的是姓名,則輸出學生的成績
題解: 直接模擬即可,但是由於n和m比較大,直接查詢會超時,但是由於成績的範圍都是1到100,所以可以首先預處理出1到100分的答案,查詢的時候直接輸出即可
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int const N = 1e5 + 10;
int n, m;
unordered_map<string,PIII> mp;
unordered_map<int,set<string>> grade_name;
string g[N];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
for(int i=0;i<n;i++){
string name;
int grade,sex,num;
cin>>name>>grade>>sex>>num;
PII sex_num={sex,num};
mp[name]={grade,sex_num};
grade_name[grade].insert(name);
}
for(auto it=grade_name.begin();it!=grade_name.end();it++){
string s="";
for(auto i=it->second.begin();i!=it->second.end();i++){
s=s+(*i);
s+="\n";
}
g[it->first]=s;
}
cin>>m;
while(m--){
int t;
cin>>t;
if(t==1){
string name;
cin>>name;
//PIII gsn = mp[name];
cout<<mp[name].first<<" "<<mp[name].second.second<<" "<<mp[name].second.first<<endl;
}
else{
int grade;
cin>>grade;
cout<<g[grade];
}
}
return 0;
}
G 貪吃的派蒙
題意: n個人,k份蛋糕。每個人都可以有一個飯量ai,每次輪到一個人的時候,可以取1到ai份蛋糕。但是這n個人裡面有一個貪心者派蒙,他是ai最大的那個人,他一定會取走ai份飯。所以現在大家想讓他刷盤子,也就是最後一個取完蛋糕,問能否使他最後一個取完全部的蛋糕。注意取完n個人一輪後,如果還有蛋糕,則從第1個人開始取第二輪
題解: 直接每一輪模擬即可,從左到右算最小值和最大值,看能否將派蒙包含進裡面即可
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, k, t;
queue<LL> q;
int main() {
cin >> t;
while (t--) {
cin >> n >> k;
LL p = 0;
while(!q.empty()) q.pop();
for (int i = 0; i < n; i++) {
LL x;
cin >> x;
p = max(p, x);
q.push(x);
}
LL l = 0, r = 0;
while (1) {
LL x = q.front();
q.pop();
if (x == p) {
r += x;
if (k > l && k <= r) {
cout << "YES\n";
break;
}
if (k <= l) {
cout << "NO\n";
break;
}
l += x;
} else {
l++;
r += x;
}
q.push(x);
}
}
return 0;
}
H 數羊
題意: 給出n和m的值,求A(n,m):
題解: 先暴力打表,然後找出規律即可:
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
LL n, m, T;
LL qmi(LL a, LL k, LL p) {
LL res = 1 % p; // res記錄答案, 模上p是為了防止k為0,p為1的特殊情況
while(k) { // 只要還有剩下位數
if (k & 1) res = (LL)res * a % p; // 判斷最後一位是否為1,如果為1就乘上a,模上p, 乘法時可能爆int,所以變成long long
k >>= 1; // 右移一位
a = (LL) a * a % p; // 當前a等於上一次的a平方,取模,平方時可能爆int,所以變成long long
}
return res;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> T;
while(T--) {
cin >> n >> m;
if (n == 1) cout << 2 << endl;
else if (n == 2) cout << 4 << endl;
else if (!m) cout << (n + 2) % 998244353 << endl;
else if (m == 1) cout << n * 2 % 998244353 << endl;
else cout << 8 * qmi(2, n - 3, 998244353) % 998244353 << endl;
}
return 0;
}
I 買花
題意: n個花,分k天買(k>1,即不能一天全買完),第一天可以買任意朵花,之後每一天買花的數量為前一天的兩倍。
問能否在15天內買夠n朵花
題解: 設第一天買的花為x個,那麼買2天就是買2x+x個,買3天就是買4x+2x+x個…
所以可以列舉買2到15天的情況,也就是列舉能買到x的倍數,然後看n能否整除某個倍數即可
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main() {
cin >> t;
while (t--) {
cin >> n;
int flag = 0;
for (int i = 2; i <= 15; i++) {
if (n % ((1 << i) - 1) == 0) {
flag = 1;
}
}
if (flag) cout << "YE5" << endl;
else
cout << "N0" << endl;
}
return 0;
}
J 這是一題簡單的模擬
題意: 從0號點出發到n個城市,然後返回0號點
現在給出所有的路徑,以及k個方案
問花費最少的方案的花費是多少
題解: 直接模擬即可…
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 3e2 + 10;
int n, m, k;
int g[MAXN][MAXN];
unordered_map<int, int> mp;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
memset(g, -1, sizeof g);
for (int i = 1, a, b, c; i <= m; ++i) {
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;
}
cin >> k;
LL res = 1e18;
while(k--) {
int t;
cin >> t;
int curpos = 0;
LL tmp = 0, flg = 1;
mp.clear();
for (int i = 1, p; i <= t; ++i) {
mp[curpos]++;
// cout << "cur: " << curpos << endl;
cin >> p;
if (g[curpos][p] != -1) {
tmp += g[curpos][p];
curpos = p;
}
else {
flg = 0;
}
}
mp[curpos]++;
if (g[curpos][0]) tmp += g[curpos][0];
else flg = 0;
for (int i = 1; i <= n; ++i) if (mp[i] != 1) {
flg = 0;
// cout << "ev: " << i << endl;
}
if (flg) {
res = min(res, (LL)tmp);
}
}
if (res != 1e18) cout << res << endl;
else cout << -1 << endl;
return 0;
}
K 黑洞密碼
題意: 輸入一個字串,然後進行如下操作:
1.確定訊息的長度為32;
2.字串中第 4 n + 1 ∼ 4 n + 4 4n+1\sim4n+4 4n+1∼4n+4的字母和第 4 n + 1 ∼ 4 n + 4 4n+1\sim4n+4 4n+1∼4n+4的數字為一組,共4組;
3.每組的第1,2,3,4個字元分別往後推每組第1,2,3,4個數字個數 例:如第一個字母為a,第一個數字為3,轉換後變為d,‘z’之後是’B’,‘Z’之後是’b’;
4.將每組內部字母的順序顛倒;
5.將四組字符合並就是最後的訊息。
題解: 直接模擬,但是需要注意的是,題目中說了z如果往後移動1位那麼會變為B,Z移動一位會變為b,比較坑
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
string s;
char ch[50], num[50];
string biao =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int main() {
cin >> s;
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9')
num[++cnt1] = s[i];
else
ch[++cnt2] = s[i];
}
string res = "";
for (int i = 0; i <= 3; i++) {
string temp = "";
for (int j = 1; j <= 4; j++) {
char now;
if(ch[i * 4 + j]>='a'&&ch[i * 4 + j]<='z'){
now = biao[ch[i * 4 + j]-'a' + num[i * 4 + j] - '0'];
if (now >= 'A' && now <= 'Z') now++;
}
else {
now = biao[ch[i * 4 + j]-'A'+26 + num[i * 4 + j] - '0'];
if (now >= 'a' && now <= 'z') now++;
}
temp.push_back(now);
}
//cout << temp << endl;
reverse(temp.begin(),temp.end());
res = res + temp;
}
cout << res << endl;
return 0;
}
L 建立火車站
題意: 給出n個城市,在這些城市之間可以建立k個車站,問最遠的兩個車站的最小值是多少(城市也需要看做車站)
需要注意車站位置必須是整數。
題解: 首先將每個區間的距離扔到優先佇列裡,然後每次都將隊頭的元素多加一個車站,然後再扔到優先佇列裡即可
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double, double> PII;
int const N = 2e5 + 10;
int n, k;
double a[N];
priority_queue<PII, vector<PII>, less<PII> > q;
int main() {
cin >> n >> k;
cin >> a[1];
for (int i = 2; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 2; i <= n; i++) {
q.push({a[i] - a[i - 1], 1});
}
while (k--) {
PII t = q.top();
double num = t.second;
double p = t.first * num;
q.pop();
q.push({p / (num + 1), num + 1});
}
cout << ceil(q.top().first) << endl;
//printf("%lld\n", ceil(q.top().first));
return 0;
}