A - Strange Birthday Party
越大的人应该获得更小价值的礼物。
证明:有两个人,其中
,有两个礼物价值分别是
,其中
。当
分别获得礼物
,付出的代价是
。当
分别获得礼物
,付出的代价是
。
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
int n , m ;
cin >> n >> m ;
vector<int> k(n) ;
vector<int> c(m + 1) ;
for(int i = 0 ; i < n ; i ++) cin >> k[i] ;
for(int i = 1 ; i <= m ; i ++) cin >> c[i] ;
sort(k.begin() , k.end()) ;
long long ans = 0 ;
int now = 1 ;
for(int i = n - 1 ; i >= 0 ; i --)
{
if(now <= k[i])
{
ans += c[now] ;
now ++ ;
}
else
{
ans += c[k[i]] ;
}
}
cout << ans << '\n' ;
}
return 0 ;
}
B - Strange Definition
是平方数等价于
是平方数。
把内每个数的偶数个数的因子都去除掉,去除后的相同的数认为是一类。
在一秒后,类的大小是偶数的类,全是1的类可以合并。
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
ios ;
int T ;
vector<int> id(1000001 , 0) ;
function<void()> init = [&]()
{
for(int i = 1 ; i <= 1000000 ; i ++) id[i] = i ;
for(int i = 2 ; i <= 1000000 ; i ++)
{
for(int j = i ; j <= 1000000 ; j += i)
{
int cnt = 0 ;
while(id[j] % i == 0)
{
id[j] /= i ;
cnt ++ ;
}
if(cnt % 2 == 1) id[j] *= i ;
}
}
} ;
cin >> T ;
init() ;
while(T --)
{
int n , q ;
cin >> n ;
vector<int> v(n) ;
for(int i = 0 ; i < n ; i ++)
{
int x ;
cin >> x ;
v[i] = id[x] ;
}
int ans = 0 ;
int ans2 = 0 ;
sort(v.begin() , v.end()) ;
for(int i = 0 ; i < n ; i ++)
{
int j = i ;
while(j + 1 < n && v[j + 1] == v[j]) j ++ ;
if((j - i + 1) % 2 == 0 || v[i] == 1) ans2 += j - i + 1 ;
ans = max(ans , j - i + 1) ;
i = j ;
}
cin >> q ;
while(q --)
{
long long w ;
cin >> w ;
if(w >= 1) cout << max(ans , ans2) << '\n' ;
else cout << ans << '\n' ;
}
}
return 0 ;
}
C - Strange Shuffle
这道题目有一些抽象,主要是考察打表能力。
打表之后会发现,每次迭代会增加一个大于的数。并且这些大于
的数是连续的。先花费
的次数产生一个
的连续大于
的段,再花费
的次数找到一个大于
的数。
然后发现,并且递增的长度为
的段只有一个,通过三分找到这个段。
#include<bits/stdc++.h>
using namespace std ;
int n , k ;
int ask(int x)
{
if(x > n) x -= n ;
printf("? %d\n" , x) ;
fflush(stdout) ;
int ans ;
scanf("%d" , &ans) ;
return ans ;
}
int main()
{
cin >> n >> k ;
int block = (int)(sqrt(n)) - 1 ;
for(int i = 1 ; i <= block ; i ++) ask(1) ;
int now = 1 ;
int l , r ;
for(int i = 1 ; i <= n ; i ++)
{
if(ask(now) > k)
{
l = now ;
r = now + n - 1 ;
break ;
}
else now += block ;
if(now > n) now -= n ;
}
int ans = l ;
while(l <= r)
{
int lmid = (2 * l + r) / 3 ;
int rmid = (2 * r + l + 2) / 3 ;
if(ask(lmid) < ask(rmid)) ans = lmid , r = rmid - 1 ;
else ans = rmid , l = lmid + 1 ;
}
ans ++ ;
if(ans > n) ans -= n ;
printf("! %d\n" , ans) ;
return 0 ;
}
D - Strange Housing
好吧,比赛时候就算写了这题,也会因为一个细节。因为有
。
很容易发现如果是个连通图,肯定是,
的时候能涂色就涂色即可。如果不是个连通图,就是
。
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
int n , m ;
cin >> n >> m ;
vector<vector<int>> g(n + 1) ;
for(int i = 1 ; i <= m ; i ++)
{
int u , v ;
cin >> u >> v ;
g[u].push_back(v) ;
g[v].push_back(u) ;
}
function<bool()> can = [&]()
{
queue<int> q ;
q.push(1) ;
vector<bool> vis(n + 1 , false) ;
vis[1] = true ;
while(!q.empty())
{
int u = q.front() ;
q.pop() ;
for(auto v : g[u]) if(!vis[v]) vis[v] = true , q.push(v) ;
}
for(int i = 1 ; i <= n ; i ++) if(!vis[i]) return false ;
return true ;
} ;
if(!can())
{
cout << "NO\n" ;
continue ;
}
vector<int> c(n + 1 , -1) ;
function<void()> bfs = [&]()
{
queue<int> q ;
q.push(1) ;
c[1] = 1 ;
while(!q.empty())
{
int u = q.front() ;
q.pop() ;
bool flag = 0 ;
for(auto v : g[u]) if(c[v] == 1) flag = 1 ;
if(flag) c[u] = 0 ;
else c[u] = 1 ;
for(auto v : g[u]) if(c[v] == -1) q.push(v) , c[v] = 0 ;
}
} ;
bfs() ;
cout << "YES\n" ;
int cnt = 0 ;
for(int i = 1 ; i <= n ; i ++) if(c[i] == 1) cnt ++ ;
cout << cnt << '\n' ;
for(int i = 1 ; i <= n ; i ++) if(c[i] == 1) cout << i << ' ' ;
cout << '\n' ;
}
return 0 ;
}