8.10 18级牛客多校第十场

比赛过程

  这第十场有点自闭,前面手速满了,签到题没有尽快写出来,还是太过犹豫。

题解

A

题意

  给出 n,求长度为n-1的permutation,要求对于每个i都有pi+1=2p(mod p)或pi+1=3p(mod p)

解法

  就是随便取一个数开头,每次能乘 2 就乘 2 不行就乘 3。题解解释就是考虑x向 x ∗ 2 x*2 x2连边,那么形成了若干个环,并且同一个环内的数 ∗ 3 *3 3 会同时连向另外同一个环。

代码
int main(){
    IO;
  int T;
  cin >> T;
  while(T--){
    int p;
    cin >> p;
    ll now = 1;
    int f = 1;
    map<int, int> mp;
    vector<int> ans;
    mp[now] = 1;
    ans.push_back(1);
    FOR(i,1,p-2){
      if(!mp[now*2%p]) {
        now = now * 2 % p;
        mp[now] = 1;
        ans.push_back(now);
      }
      else if(!mp[now*3%p]){
        now = now * 3 % p;
        mp[now] = 1;
        ans.push_back(now);
      }
      else
        f = 0;
    }
    if(f){
      for(auto i:ans){
        cout << i << " ";
      }
    }
    else
      cout << -1;
    cout << endl;
  }
  return 0;
}

E

题意

  题意不太好描述,看这里

解法

  这个真就猜呗,说实话我也证明不出来,题解也就这么一句话,二分还是稳,但我选择直接猜一手最大前缀平均值。其实当时比赛写烦了,其实不用开数组。

代码
ll a[maxn];
int main()
{
	IO;
	int t;
	cin >> t;
	while (t--)
	{
		ll sum = 0;
		int n;
		cin >> n;
		ll ma = 0;
		re(i, 1, n)
		{
			cin >> a[i];
			sum += a[i];
			ll te=sum/i+(sum%i!=0);
			ma = max(ma, te);
		}
		cout << ma << endl;
	}
}

J

题意

给定两个均含有n个节点的树T1,T2,每个节点的权值在1~n范围内。如果这两个树满足:树根的权值相同;对于任意非根节点,其父节点权值也应相同。现在你要改变T1的节点权值使得T1=T2,问最少需要改变的节点数。

解法

dp[x][y]表示以左边的树x为根,右边的树y为根,他们有dp[x][y]个序号是重合的,若x和y不同构那就dp[x][y] = -INF;
第一步利用get函数获得每一种树的形式编号,tot1[x] = tot2[y]就代表x和y同构,
第二步就跑费用流,每次跑都重新建图(删除之前建过的图)
如何转移?
给x的儿子们和y的儿子们建个二分图跑最大权值匹配,跑下来的最大权值就是儿子们的答案。

代码
int n, tot, ans;
// MCMF费用流代码
int head[N], ver[M], nex[M], edge[M], cost[M];
int vis[N], dis[N], incf[N], pre[N];

void init() {
   tot = 1;
   ms(head, 0);
}

void add(int x, int y, int z, int c) {
   ver[++tot] = y, edge[tot] = z, cost[tot] = c, nex[tot] = head[x], head[x] = tot;
   ver[++tot] = x, edge[tot] = 0, cost[tot] = -c, nex[tot] = head[y], head[y] = tot;
}

bool spfa(int s, int t) {
   queue<int> q;
   ms(dis, inf), ms(vis, 0);
   q.push(s), dis[s] = 0, vis[s] = 1;
   incf[s] = INF;
   while(!q.empty()) {
      int x = q.front(); q.pop(); vis[x] = 0;
      for(int i = head[x]; i; i = nex[i]) {
         int y = ver[i];
         if(dis[y] > dis[x] + cost[i] && edge[i]) {
            dis[y] = dis[x] + cost[i];
            incf[y] = min(incf[x], edge[i]);
            pre[y] = i;
            if(!vis[y]) vis[y] = 1, q.push(y);
         }
      }
   }
   if(dis[t] == INF) return false;
   return true;
}

void update(int s, int t, int &flow) {
   int x = t;
   while(x != s) {
      int i = pre[x];
      edge[i] -= incf[t], edge[i^1] += incf[t];
      x = ver[i ^ 1];
   }
   flow += incf[t];
   ans += dis[t] * incf[t];
}

int solve(int s, int t, int &flow) {
   ans = 0;
   while(spfa(s, t)) update(s, t, flow);
   return ans;
}
// 树上dp
ll dp[550][550];
vector<int>G1[N], G2[N];
map<string, int> id;
int judge[550][550];
int aans = 0, tot1[550], tot2[550];

int dfs(int x, int y) {
   // x和y是否同构
   if(!judge[x][y]) {
      dp[x][y] = -INF;
      return 0;
   }
   if(x == y) {
      dp[x][y] = 1;
      if(!G1[x].size()) return 0;
   }
   rep(i, 0, G1[x].size()-1) rep(j, 0, G2[y].size()-1) {
      int a = G1[x][i];
      int b = G2[y][j];
      dfs(a, b);
   }
   init();
   rep(i, 0, G1[x].size() - 1) add(2010, i, 1, 0);
   rep(j, 0, G2[y].size() - 1) add(j+505, 2011, 1, 0);

   rep(i, 0, G1[x].size() - 1) 
      rep(j, 0, G2[y].size() - 1) {
         int a = G1[x][i];
         int b = G2[y][j];
         add(i, j+505, 1, -dp[a][b]);
   }
   int cntt = 0;
   int ans = solve(2010, 2011, cntt);
   dp[x][y] -= ans;
   return 0;
}

void get(int x, int y) {
   rep(i, 0, G1[x].size() - 1) 
      rep(j, 0, G2[y].size() - 1) {
         int a = G1[x][i];
         int b = G2[y][j];
         get(a, b);
   }
   string str;
   if(G1[x].size() == G2[y].size()) {
      if(!G1[x].size()) judge[x][y] = 1;
      else {
         for(auto tmp : G1[x]) str += (char)(tot1[tmp] + '0');
         sort(str.begin(), str.end());
         if(!id[str]) id[str] = ++aans;
         tot1[x] = id[str];
         str.clear();

         for(auto tmp : G2[y]) str += (char)(tot2[tmp] + '0');
         sort(str.begin(), str.end());
         if(!id[str]) id[str] = ++aans;
         tot2[y] = id[str];
         str.clear();

         if(tot1[x] == tot2[y]) judge[x][y] = 1;
      }
   }
}

int main() {
   scanf("%d", &n);
   int rt1, rt2;
   rep(i, 1, n) {
      int x; scanf("%d", &x);
      if(!x) rt1 = i;
      else G1[x].pb(i);
   }
   rep(i, 1, n) {
      int x; scanf("%d", &x);
      if(!x) rt2 = i;
      else G2[x].pb(i);
   }
   rep(i, 1, n) dp[i][i] = 1;
   get(rt1, rt2);
   dfs(rt1, rt2);
   printf("%d\n", n - dp[rt1][rt2]);
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值