A. Groundhog and 2-Power Representation
题意
一个数可以由2x1+2x2+2x3+.....组成,例如1315=210+28+25+2+1=2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0).
现在给出一个由2的次幂组成的表达式,输出这个数是多少。
题解
不得不说py真的强,看到不到2分钟就有人a了,还以为是原题,赛后发现py三行。(暴风哭泣
我队用的c++高精度模拟写的,队友%%%
代码
py
n = input()
n = n.replace("(","**(")
print(eval(n)) c++
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 3e4+10;
vector<int> mult(vector<int>x,vector<int>y)//高精*高精
{
int xlen=(int)x.size(),ylen=(int)y.size(),zlen=xlen+ylen;
vector<int>z(zlen);
for(register int i=0;i<xlen;i++)
for(register int j=0;j<ylen;j++)
z[i+j]+=x[i]*y[j];
for(register int i=0;i<zlen;i++)
if(z[i]>9)
{
z[i+1]+=z[i]/10;
z[i]%=10;
}
while(zlen>1 && !z.back())
{
z.pop_back();
zlen--;
}
return z;
}
vector<int> chu(int x,vector<int> vv)
{
bool flag=false;
vector<int> ans;
int t=0;
int i;
for (i=vv.size()-1; i>=0; i-- )
{
t=t*10+vv[i];
if(flag)
{
ans.push_back(t/x);
}
else if(t/x>0)
{
flag=true;
ans.push_back(t/x);
}
t=t%x;
}
return vector<int> (ans.rbegin(),ans.rend());
}
vector<int> add(vector<int>x,vector<int>y)//高精+高精
{
int xlen=(int)x.size(),ylen=(int)y.size(),zlen=max(xlen,ylen)+1;
vector<int>z(zlen);
for(register int i=0;i<zlen;i++)
{
if(i<xlen)
z[i]+=x[i];
if(i<ylen)
z[i]+=y[i];
if(z[i]>9)
{
z[i+1]++;
z[i]-=10;
}
}
while(zlen>1 && !z.back())
{
zlen--;
z.pop_back();
}
return z;
}
void prin(vector<int> x)
{
int i;
if(x.size() == 0)
{
printf("0");
}
for (i=x.size()-1;i>=0;i--)
{
printf("%d",x[i]);
}
printf("\n");
}
std::vector<int> qup(std::vector<int> vv)
{
std::vector<int> ans;
ans.pb(1);
std::vector<int> v;
std::vector<int> f;
f.pb(0);
v.pb(2);
while(vv.size() > 0 && *(--vv.end()) != 0)
{
if(vv[0] & 1)
ans = mult(v,ans);
vv = chu(2,vv);
v = mult(v,v);
}
return ans;
}
char a[maxn];
vector<int> dg(int l,int r)
{
vector<int> ans;
if(l == r)
{
ans.pb(a[l] - '0');
return ans;
}
ans.pb(0);
std::vector<int> temp;
for (int i = l; i <= r; i ++ )
{
if(a[i] == '(')
{
int s= 0 ;
for(int j = i + 1; j <= r; j ++ )
{
if(a[j] == '(')
s ++ ;
if(a[j] == ')')
{
if(s == 0)
{
ans = add(ans,qup(dg(i + 1, j - 1)));
i = j;
break;
}
else
s -- ;
}
}
continue;
}
if(a[i] == '+')
{
ans = add(ans,dg(i + 1,r));
break;
}
else
{
if(a[i + 1] != '(')
{
temp.pb(a[i] - '0');
ans = add(ans,temp);
}
continue;
}
}
return ans;
}
int main()
{
scanf("%s",a + 1);
int n = strlen(a + 1);
vector<int> ans = dg(1,n);
prin(ans);
} E. Groundhog Chasing Death
题意
给出a,b,c,d,x,y,求
modulo 998244353的结果
题解
第一想法肯定是暴力:枚举 i 和 j ,然后算出每一个 gcd(xi , yj),然后乘起来。但是数据 i 和 j 的数据范围都在1e6,这样肯定会超时,i 和 j 的范围在1e9,这样肯定是要爆long long的。那么就要想想怎么优化。
因为这是一个乘性函数,那么肯定要想到分解质因子,所以先预处理 x 的质因子,并记录每个质因子出现的次数,这样 xi 就可以由每个质因子个数再 *i 得到。枚举 xi 中因子 m 出现的次数,可以发现当 yj 小的时候,gcd(xi , yj) 主要是被 yj 的 m 个数约束,此时是一个等差数列;当 yj 大的时候,就是由 xi 约束,此时 yj 中 m 的个数是一个常数,暴力求解就好了。
由于质因子的幂很大,会爆long long,所以要用欧拉降幂,欧拉降幂是对mod-1取模(队友对mod取模debug好久
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const ll md = 998244352;
vector<pair<ll,ll> > v;
void div(ll n)
{
v.clear();
ll k = sqrt(n);
for (ll i = 2; i <= k; ++ i) {
ll cnt = 0;
while (n % i == 0) {
n /= i;
cnt ++;
}
v.push_back({i, cnt});
}
if (n != 1) {
v.push_back({n, 1});
}
}
ll phi(ll n)
{
ll ans = n;
ll k = sqrt(n);
for (int i = 2; i <= k; ++i) {
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
}
if (n > 1) {
ans = ans / n * (n - 1);
}
return ans;
}
ll pow(ll a, ll b, ll p) {
ll res = 1;
while (b) {
if (b & 1) res = (res * a) % p;
a = a * a % p;
b >>= 1;
}
return res%p;
}
int main()
{
ll a, b, c, d, x, y;
scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y);
a = max(1LL, a);
c = max(1LL, c);
--c;
div(x);
ll ans = 1;
for (int i = 0; i < (int)v.size(); ++ i) {
ll cnt = 0;
while (y % v[i].first == 0) {
y /= v[i].first;
++ cnt;
}
ll sum = 0;
if (cnt == 0) continue;
for (ll j = a; j <= b; ++ j) {
ll e = v[i].second * (ll)j;
ll f = e/cnt;
while (cnt * f < e) {
++ f;
}
if (c >= f) {
sum -= ((f * (f-1) / 2)% md * (cnt % md)) % md;
sum = (sum % md + md) % md;
sum -= (ll)(((c-f+1) % md) * (e % md)) % md;
sum = (sum % md + md) % md;
}
else {
sum -= ((c * (c+1) / 2) % md * (cnt % md)) % md;
sum = (sum % md + md) % md;
}
sum = (sum % md + md) % md;
if (d >= f) {
sum += ((f * (f-1) / 2) % md) * (cnt % md) % md;
sum = (sum % md + md) % md;
sum += (ll)(((d-f+1) % md) * (e % md)) % md;
sum = (sum % md + md) % md;
}
else {
sum += (((d * (d+1) /2) % md) * (cnt) % md) % md;
sum = (sum % md + md) % md;
}
}
sum = (sum % md + md) % md;
ans *= pow(v[i].first, sum, mod);
ans = (ans % mod + mod) % mod;
}
ans = (ans % mod + mod) % mod;
printf("%lld\n", ans);
return 0;
}
F. Groundhog Looking Dowdy
题意
土拨鼠要和苹果约会,第 i 天它的第 j 件衣服的邋遢度为 aij ,它要在n天中选择m天和苹果约会,要求选出的m天衣服的邋遢度的最大值和最小值的差值最小。
题解
因为要最小化最大值和最小值的差值,所以用pair存每件衣服的邋遢度和第几天,然后对邋遢度从小到大排序。那么问题就转换成了求一个区间 [L,R] ,使得这个区间覆盖m个不同的天,并且R的邋遢度-L的邋遢度最小。这个问题就可以用尺取解决了。对于每一个L,求出最小的合法的R,每次更新差值最小值即可。
代码
#include<bits/stdc++.h>
#define st first
#define sd second
#define ll long long
#define pii pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6+10;
pii pp[maxn];
int vis[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int cnt = 0;
for (int i = 1; i <= n; i ++ ){
int p;
scanf("%d",&p);
for (int j = 1; j <= p; j ++ ){
int x;
scanf("%d",&x);
pp[++cnt].st = x;
pp[cnt].sd = i;
}
}
sort(pp + 1, pp + 1 + cnt);
int num = 0;
int l = 1, r = 1;
int minn = pp[1].st, maxx = 0;
int ans = inf;
while(1){
while(r <= cnt && num < m){
if(vis[pp[r].sd] == 0) num ++ ;
vis[pp[r].sd] ++ ;
maxx = pp[r].st;
r ++ ;
}
if(num < m)
break;
ans = min(ans, maxx - minn);
vis[pp[l].sd] -- ;
if(vis[pp[l].sd] == 0) num -- ;
minn = pp[l + 1].sd;
l ++ ;
}
printf("%d\n",ans);
} I. The Crime-solving Plan of Groundhog
题意
给出n个数(0<=a[i]<=9),由这n个数组成2个数,使得这两个数的乘积最小。
题解
自己造几个例子就可以看出,选择0之外最小的数和剩下的数字组成的没有前导0的数相乘结果最小。剩下的数字怎样最小呢,当然是找到最小的非零的数做第一位,后边接上所有的0,再按照有小到大的顺序放剩下的数字。因为n的范围在1e5,所以要用高精度乘法。
推导:
把当前的数字拆成4个数 a, b, c, d (a ≤ b ≤ c ≤ d) ,那么我们有两种决策:两位数×两位数,或者三位数×一
位数。
(10a + d) * (10b + c) = 100ab + 10ac + 10bd + cd (100b+10c+d) * a = 100ab + 10ac +ad<(10a + d) * (10b + c)
同理,可以证明留一个最小的正整数作为第一个数,剩下的所有数字排成最小的数作为第二个数时,答案取到最小值。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[100100];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
int k=0;
while(k<n&&a[k]==0) k++;
vector<int>q;
q.push_back(a[k+1]);
for(int i=0;i<k;i++) q.push_back(0);
for(int i=k+2;i<n;i++) q.push_back(a[i]);
vector<int>ans;
for(int i=q.size()-1;i>=0;i--){
int x=q[i]*a[k];
ans.push_back(x);
}
for(int i=0;i<10;i++) ans.push_back(0);
for(int i=0;i<ans.size();i++){
if(ans[i]>=10){
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
}
while(!ans.back()) ans.pop_back();
for(int i=ans.size()-1;i>=0;i--) cout<<ans[i];
cout<<endl;
}
return 0;
}
K. The Flee Plan of Groundhog
题意
土拨鼠在第1个宿舍,橙子在第n个宿舍。这n个宿舍间有n-1条路并且长度都为1,土拨鼠从第1个房间去第n个宿舍,速度为1m/s;橙子从第n个宿舍追赶土拨鼠,速度为2m/s。
题解
二分时间 t ,然后判断在 ts 内土拨鼠是否会被橙子追上。以橙子所在的寝室 n 为根建树,从 1 到 n 枚举所有土拨鼠能够到达的点,先找出t秒能走到哪个点,然后再找这个点能走到的离n最远的点,判断在走的过程中会不会被追上。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
vector<int> vv[maxn];
int vis[maxn];
int f[maxn];
int dep[maxn];
void dfs(int x,int fa,int de)
{
f[x] = fa;
dep[x] = de;
for (int i =0 ; i< vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs(v,x,de + 1);
vis[x] |= vis[v];
}
}
int ans =0 ;
void dfs2(int x,int fa,int de)
{
ans = max(ans,de);
for (int i =0 ; i<vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs2(v,x,de + 1);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for (int i = 1; i < n; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
vv[x].push_back(y);
vv[y].push_back(x);
}
vis[1] = 1;
dfs(n,0,1);
int k = -1;
int s = dep[1] - m;
for (int i = 1; i <= n; i ++ ){
if(vis[i] && dep[i] == s){
k = i;
break;
}
}
int num = dep[k] - 1;
dfs2(k,f[k],1);
ans -- ;
num += ans;
int r = (num + 1) / 2;
int l = 0;
while(l < r){
int mid = l + r>> 1;
int x = min(2 * mid,num);
int y = min(mid, ans);
if(x - dep[k] + 1>= y) r = mid;
else l = mid + 1;
}
printf("%d\n",l);
} 
京公网安备 11010502036488号