2017廣東工業大學ACM新生杯初賽
阿新 • • 發佈:2019-01-22
真想再體驗一把新生杯。(部分題解)
Problem A: Chinese Remainder Theorem
思路:中國剩餘定理,套個板子就行了,注意輸入的資料要去重。# include <iostream> # include <cstdio> # include <cstring> using namespace std; typedef long long LL; const int maxn = 20; int n; LL m[maxn], r[maxn]; int vis[20][20]; LL extend_Euclid(LL a, LL b, LL &x, LL &y)//擴充套件歐幾里得。 { if(b==0) { x = 1; y = 0; return a; } LL r = extend_Euclid(b, a%b, y, x); y -= a/b*x; return r; } LL China() { LL M = 1, ans = 0; for (int i = 0; i < n; ++i) M *= m[i]; for(int i = 0;i < n;i++) { LL N = M/m[i]; LL x, y; extend_Euclid(N, m[i], x, y); x = (x%m[i] + m[i]) % m[i]; ans = ((ans+r[i]*N%M*x%M)%M + M) % M ; } return (M+ans%M)%M; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); int i,cnt=0; memset(vis, 0, sizeof(vis)); for(i=0; i<n; ++i) { LL tx, ty; scanf("%lld%lld",&tx,&ty); if(!vis[tx][ty] == 1) { vis[tx][ty] = 1; r[cnt] = tx; m[cnt++] = ty; } } n = cnt; LL ans = China(), f=1; for(int i=0; i<n; ++i) { if(ans%m[i] != r[i]) { f = 0; puts("IMPOSSIBLE"); break; } } if(f) printf("%lld\n",ans); } return 0; }
Problem B: AC的概率
思路:根據同餘定理,(a+b)%6==0,有(a%6+b%6)%6 == 0,將每個數先取模6,同時記錄到陣列b上,掃一遍即可。# include <bits/stdc++.h> using namespace std; const int maxn = 1e5+30; int a[maxn]; int main() { int t, n; scanf("%d",&t); while(t--) { int b[7]={0}; scanf("%d",&n); double tot = (double)n*(n-1)/2, sum=0; for(int i=0; i<n; ++i) { scanf("%d",&a[i]); a[i] %= 6; if(a[i] == 0) sum += b[a[i]]; else sum += b[6-a[i]]; ++b[a[i]]; } printf("%.6f\n",sum*1.0/tot); } return 0; }
Problem D: 好難啊
思路:目測是CF Div2的一道題,先不考慮最後一行和最後一列,任意填充前(n-1)*(m-1)個格,那麼最後一行和最後一列顯然可以填上1或-1使得每行每列都等於k,那麼右下角那個格子呢?設前(n-1)*(m-1)個格乘積為sum,對於列來說,右下角填上A=k^(n-1)*sum,對於行來說右下角填上B=k^(m-1)*sum。那麼顯然如果k=-1,且n和m奇偶性不同時A不等於B,其餘情況都能滿足。# include <iostream> # include <cstdio> # include <cstring> using namespace std; typedef long long LL; int main() { LL n, m, k; while(~scanf("%lld%lld%lld",&n,&m,&k)) { if((n&1) != (m&1) && k == -1) puts("Orz"); else puts("O(^_^)O~~"); } return 0; }
Problem E: 工會首領yjl
思路:貪心,先按Q值排序,所有人得到ceil(Q/2)元,剩下的錢倒著派發,Q值大的先派發。# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
typedef long long LL;
struct node
{
int x, id;
}a[103];
int ans[103];
bool cmp(node a, node b)
{
return a.x < b.x;
}
int main()
{
int n, m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0; i<n; ++i)
{
scanf("%d",&a[i].x);
a[i].id = i;
}
sort(a, a+n, cmp);
int sum = 0, sum2=0;
for(int i=0; i<n; ++i)
{
int tmp = (int)ceil(a[i].x/2.0);
ans[a[i].id] = tmp;
sum += tmp;
sum2 += a[i].x;
}
if(sum > m || sum2 < m)
{
puts("gg");
continue;
}
int rest = m-sum;
for(int i=n-1; i>=0; --i)
{
int id = a[i].id;
int imin = min(rest, a[i].x-ans[id]);
if(i < n-1) imin = min(imin, ans[a[i+1].id]-ans[id]);
ans[id] += imin;
rest -= imin;
}
for(int i=0; i<n; ++i)
printf("%d ",ans[i]);
puts("");
}
return 0;
}
Problem F: 位數是多少?
思路:計算一個數x的位數是log10(x)+1,計算log10(a^b)+1可以化為b*log10(a)+1。# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
typedef long long LL;
using namespace std;
int main()
{
int x, y, t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&x,&y);
printf("%d\n",(int)(y*log10(x))+1);
}
return 0;
}
Problem G: 一道簡單的題目
思路:就是直接做,但是資料我故意加了一堆1進去...所以預處理每個1右邊的首個非1數的位置即可,不然會超時。
# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
const int maxn = 1e5+30;
int a[maxn], r[maxn];
int main()
{
int n, q, L, R, K;
while(~scanf("%d%d",&n,&q))
{
memset(r, 0, sizeof(r));
memset(a, 0, sizeof(a));
for(int i=1; i<=n; ++i) scanf("%d",&a[i]);
r[n] = n+1;
for(int i=n-1; i>=1; --i)
{
if(a[i+1] == 1) r[i] = r[i+1];
else r[i] = i+1;
}
while(q--)
{
scanf("%d%d%d",&L,&R,&K);
for(int i=L; i<=R; i=r[i])
{
K /= a[i];
if(K==0) break;
}
printf("%d\n",K);
}
}
return 0;
}
Problem H: 一棵二叉樹
思路:子節點除以二就是父節點的編號,一直往上除直到一存到陣列。比較兩個點的公共祖先最大那個。#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
LL arr[500];
int main()
{
int T;
LL a,b;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&a,&b);
memset(arr,0,sizeof(arr));
int tmp=0;
while(a){
arr[tmp++]=a;
a>>=1;
}
while(b){
arr[tmp++]=b;
b>>=1;
}
sort(arr,arr+tmp);
for(int i=tmp-1;i;--i)
if(arr[i]==arr[i-1]){
printf("%lld\n",arr[i]);
break;
}
}
return 0;
}
後面的先留坑