题意: 给定一个 n n n个点的无向完全图, i i i和 j j j之间的边权是 gcd ( a i , a j ) \gcd{(a_i,a_j)} gcd(ai,aj),保证数组 a a a随机,求 MST \text{MST} MST
分析: 如果有点权为素数 p p p, ∀ x ∈ R , gcd ( p , x ) = 1 \forall x\in R,\gcd{(p,x)}=1 ∀x∈R,gcd(p,x)=1,所以如果找到素数,就以素数的点为中心,与其他点建立 n − 1 n-1 n−1条边,这样 MST \text{MST} MST的最小值为 n − 1 n-1 n−1。int
范围内的素数间距最小间距不到几百,所以在 n ≤ 1000 n \le1000 n≤1000时直接暴力, n > 1000 n>1000 n>1000时输出 n − 1 n-1 n−1。
另外,如果 L = R L=R L=R,则输出 L ∗ ( n − 1 ) L*(n-1) L∗(n−1)。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=2e5+5;
ULL seed,n,L,R,a[N],res;
ULL xorshift64(){
ULL x=seed;
x^=x<<13;
x^=x>>7;
x^=x<<17;
return seed=x;
}
int gen(){
return xorshift64()%(R-L+1)+L;
}
int main(){
cin>>n>>L>>R>>seed;
if(L==R) cout<<L*(n-1)<<endl;
else if(n<=1000){
vector<ULL> x;
for(int i=1;i<=n;i++) a[i]=gen();
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
x.push_back(__gcd(a[i],a[j]));
sort(x.begin(),x.end());
for(int i=0;i<n-1;i++) res+=x[i];
cout<<res<<endl;
}
else cout<<n-1<<endl;
}
题意: 给定一棵树,黑白染色方案,满足一个黑点的子树都是黑点,白点任意。你现在构造一棵树,使得它的染色方案数为 K K K。
分析: 首先一个节点必定有全黑的方案,所以就可以转移到子树节点的方案数,如果 K K K为奇数,那么这个节点连接一个左儿子,一个右儿子,然后 K / 2 K/2 K/2。如果 K K K为偶数,直接连一个右儿子,使 K − 1 K-1 K−1变为奇数。注意特判 K = 3 K=3 K=3的情况。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL k;
int main(){
cin>>k;
LL fa=1,id=1,tmp=k,cnt=1;
while(tmp>3){
if(tmp&1){
tmp/=2;
cnt+=2;
}
else{
tmp--;
cnt++;
}
}
if(tmp==3) cnt++;
cout<<cnt<<endl;
while(k>3){
if(k&1){
k/=2;
id++;
cout<<fa<<" "<<id<<endl;
id++;
cout<<fa<<" "<<id<<endl;
fa=id;
}
else{
k--;
id++;
cout<<fa<<" "<<id<<endl;
fa=id;
}
}
if(k==3){
id++;
cout<<fa<<" "<<id<<endl;
}
}
题意: 二维空间里放了个 n n n盒子,有水平往左和竖直往下两种重力,求重力作用之后形成的轮廓周长。
分析: 模拟。每次放的方块对答案贡献是 4 4 4,如果这行(列)被放过方块,那么答案 − 2 -2 −2,如果移动之后相邻的方块被放置过,那么答案也分别 − 2 -2 −2,只需要记录每次的高度再判断一下相邻就可以。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long LL;
LL n,x,y,res1,sx1[N],sy1[N],res2,sx2[N],sy2[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x>>y;
res1+=4;
if(sx1[x]) res1-=2;
else sx1[x]=1;
sy1[x]++;
if(sy1[x-1]>=sy1[x]) res1-=2;
if(sy1[x+1]>=sy1[x]) res1-=2;
res2+=4;
if(sy2[y]) res2-=2;
else sy2[y]=1;
sx2[y]++;
if(sx2[y-1]>=sx2[y]) res2-=2;
if(sx2[y+1]>=sx2[y]) res2-=2;
cout<<res1<<" "<<res2<<endl;
}
}
题意: 输出 ∑ i = 1 n a i n \frac{\sum^{n}_{i=1}a_i}{n} n∑i=1nai,保留小数点后 k k k位(直接截断后面的)
分析: 模拟除法。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,k,x,sum;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>x;
sum+=x;
}
cout<<sum/n<<".";
sum%=n;
while(k--){
cout<<sum*10/n;
sum*=10;
sum%=n;
}
}
题面: Yuna \text{Yuna} Yuna 的生命值是 H H H,体力值是 S S S,有 n n n个任务,每个任务有生命值和体力值的花费。生命值不能降到 0 0 0或 0 0 0以下,体力值的多余消耗会算到生命值里。求最大任务收益。
分析: 二维费用背包板子题,状态转移方程:
{ d p [ j ] [ k ] = m a x ( d p [ j ] [ k ] , d p [ j − h [ i ] + k − s [ i ] ] [ 0 ] + w [ i ] ) , if k − s [ i ] < 0 a n d j − h [ i ] + k − s [ i ] ≤ 0 d p [ j ] [ k ] = m a x ( d p [ j ] [ k ] , d p [ j − h [ i ] ] [ k − s [ i ] ] + w [ i ] ) , else \begin{cases} dp[j][k]=max(dp[j][k],dp[j-h[i]+k-s[i]][0]+w[i]),\text{if }k-s[i]<0&and&j-h[i]+k-s[i]\le 0\\ dp[j][k]=max(dp[j][k],dp[j-h[i]][k-s[i]]+w[i]),\text{else} \end{cases} { dp[j][k]=max(dp[j][k],dp[j−h[i]+k−s[i]][0]+w[i]),if k−s[i]<0dp[j][k]=max(dp[j][k],dp[j−h[i]][k−s[i]]+w[i]),elseandj−h[i]+k−s[i]≤0
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1010,M=305;
LL n,H,S,h[N],s[N],w[N],dp[M][M];
int main(){
cin>>n>>H>>S;
for(int i=1;i<=n;i++) cin>>h[i]>>s[i]>>w[i];
for(int i=1;i<=n;i++){
for(int j=H;j>h[i];j--){
for(int k=S;k>=0;k--){
if(k-s[i]<0){
if(j-h[i]+k-s[i]<=0) continue;
dp[j][k]=max(dp[j][k],dp[j-h[i]+k-s[i]][0]+w[i]);
}
else{
dp[j][k]=max(dp[j][k],dp[j-h[i]][k-s[i]]+w[i]);
}
}
}
}
cout<<dp[H][S]<<endl;
}
题意: 给定 0 / 1 0/1 0/1矩阵 C C C,构造两个矩阵 A , B A,B A,B,其中 1 1 1形成了完整的不分散的一块四连通块,并且对于 C C C中所有位置,若是 1 1 1,则 A , B A,B A,B对应位置必须都是 1 1 1,否则 A , B A,B A,B之中必须有一个这个位置为 0 0 0。保证 C C C阵的边框都是 0 0 0。
分析: 思维题。 A A A最左边一列是 1 1 1, B B B最右边一列是 1 1 1,然后行分奇偶全染成 1 1 1
#include<bits/stdc++.h>
using namespace std;
const int N=505;
char c[N][N],a[N][N],b[N][N];
int n,m;
int main(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>c[i];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(c[i][j]=='1') a[i][j]='1';
else a[i][j]='0';
if(i%2==0&&j<m-1) a[i][j]='1';
if(!j) a[i][j]='1';
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(c[i][j]=='1') b[i][j]='1';
else b[i][j]='0';
if(i%2==1&&j) b[i][j]='1';
if(j==m-1) b[i][j]='1';
}
}
for(int i=0;i<n;i++) cout<<a[i]<<endl;
for(int i=0;i<n;i++) cout<<b[i]<<endl;
}