101 | 北林一队 | 北京林业大学 | 5 | 11:20:10 |
F:模拟即可,记得开long long
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
ll a[110];
int main()
{
ll n;
scanf("%lld",&n);
ll mx=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
mx=max(mx,a[i]);
}
for(int i=1;i<=n;i++)
{
ll tp=a[i],up=(ll)50*a[i]/mx;
if(a[i]*50%mx!=0)up++;
printf("+");for(int j=1;j<=up;j++)printf("-");printf("+");puts("");
printf("|");for(int j=1;j0)
{
if(tp==mx)printf("*");else printf(" ");
}
printf("|");printf("%d",tp);puts("");
printf("+");for(int j=1;j<=up;j++)printf("-");printf("+");
puts("");
}
return 0;
}
I:
GHHEHHGHHE
HHGHHEHHGH
HEHHGHHEHH
GHHEHHGHHE
2/3
#include
using namespace std;
int main(){
puts("0.666667");
}
E:置换群最小循环节,水题,不过要JAVA大数
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static int n,len;
static int[] p = new int[200005];
static int[] vis = new int[200005];
static int[] cnt = new int[200005];
public static void main(String[] args) {
Scanner sin = new Scanner(System.in);
n=sin.nextInt();
for(int i=1;i<=n;i++){
vis[i]=cnt[i]=0;
p[i]=sin.nextInt();
}
/*n=50000;
for(int i=1;i0)
ans.remainder(mod);
}
System.out.println(ans);
}
}
D:
2操作等价于把链变成环(2操作可以无限次)
1操作等价于把一个数往前移动任意位置。
所以最后结果就是环上的LIS。
for一遍Onlogn求LIS即可。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 500+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M];
int b[M],d[M];
int n;
int LIS()
{
memset(d,0,sizeof(d));
int l,r,mid,len=1;
d[1]=a[1];
for(int i=1;i<=n;i++)
{
l=1,r=len;
if(a[i]>d[len])
{
d[++len]=a[i];
continue;
}
while(l<=r)
{
mid=(l+r)>>1;
if(d[mid]len)len++;
}
return len;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
int mn=n+7;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int tp=(j+i)%n;if(tp==0)tp=n;
a[j]=b[tp];
}
//for(int j=1;j<=n;j++)cout<
B:
最后结果肯定是MST。因为任意两点间的连边值是固定的,x-y的异或和为:f[1,x]^f[1,y]。
但这是稠密图的MST。连边很特殊。很容易想到Boruvka算法 求MST(没学过的可以看我之前写的博客)
但这个算法的瓶颈在于如何快速找到一个点到其他连通快点异或最小边权。
我们仔细观察条件,按位异或,自然的想到从高位开始。
把最高位为0的和为1的分成2组,这两组之间连一条权值最小的边,其他内部连,一定是最优解。。(根据Boruvka的思想)
因为我们目的是一直让不同连通快点连边,边权尽量小,把当前最高位01分组后,01之间必须要至少连一条边(否则最后不连通),然后0内部相连 ,1内部相连,变成两个子问题。
上述操作直接分治处理即可。(把f数组排序,每一位01一定是在两段区间的)
可以看看我之前写的这道题,很类似,只不过这题把点权改成了边权,本质是一样的。
https://blog.csdn.net/bjfu170203101/article/details/104321068
#include
using namespace std;
typedef long long ll;
const int M = 2e5+7;
int head[M],CNT=1;
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++CNT].nxt=head[x],ee[CNT].w=w,ee[CNT].to=y,head[x]=CNT;}
int a[M];
int ti[M*32][2],cnt;//字典树
ll ans;
void in(int x)
{
int k=0;
for(int i=29;i>=0;i--)
{
int id=(x>>i)&1;
if(ti[k][id]==0)
{
ti[k][id]=++cnt;
k=cnt;ti[k][0]=ti[k][1]=0;
}
else k=ti[k][id];
}
}
int fd(int x)//找到字典树中存的树与x异或最小
{
int k=0,ans=0;
for(int i=29;i>=0;i--)
{
int id=(x>>i)&1;
if(ti[k][id]==0)id^=1;
k=ti[k][id];
if(id)ans|=(1<>id)&1)==0)
mid=i;
if(l<=mid)dfs(id-1,l,mid);
if(mid+1<=r)dfs(id-1,mid+1,r);
if(l<=mid&&mid+1<=r)//这一步放在dfs前和dfs后都行
{
cnt=0;
ti[0][0]=ti[0][1]=0;
for(int i=l;i<=mid;i++)in(a[i]);
int mi=2e9;
for(int i=mid+1;i<=r;i++)
mi=min(mi,a[i]^fd(a[i]));
ans+=mi;
}
}
void dfs(int x,int fat)
{
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=ee[i].w;
if(y==fat)continue;
a[y]=a[x]^w;
dfs(y,x);
}
}
int main()
{
int n,u,v,w;
scanf("%d",&n);
for(int i=1;i<=n-1;i++)scanf("%d%d%d",&u,&v,&w),u++,v++,add(u,v,w),add(v,u,w);
dfs(1,0);
// for(int i=1;i<=n;i++)cout<