提出 #36576932


ソースコード 拡げる

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<(int)n;i++)
#define per(i,a,n) for (int i=n;i-->(int)a;)
int read(){int r;scanf("%d",&r);return r;}

class TwoSat{
  vector<int> low; // 能达到的最小的点
  vector<int> dfn; // tarjan 用的深搜访问次序标识
  stack<int> stk; // tarjan 用的stk
  vector<int> res; // tarjan 结果
  vector<vector<int> > p; // 所有点
  int n;
  void scc(int v) {
    static int id = 0;
    low[v] = dfn[v] = id++;
    stk.push(v);
    for(auto w:p[v]){
      if(dfn[w] == -1){ // 未访问过
        scc(w);
        low[v] = min(low[v],low[w]);
      } else if(res[w] == -1){ // 访问过但没有结果(在栈中)
        low[v] = min(low[v],dfn[w]);
      }
    }
    int u;
    if(low[v] == dfn[v])  {
      do{
        res[u = stk.top()] = v;
        stk.pop();
      }while(u != v);
    }
  }
  vector<vector<int> > sccgroup(){
    rep(i,0,2*n) if(res[i]==-1) scc(i);
    vector<pair<int,int> > gi;
    rep(i,0,2*n) gi.push_back({res[i],i});
    sort(gi.begin(),gi.end());
    vector<vector<int> > group;
    rep(i,0,2*n){
      if(i==0||gi[i].first != gi[i-1].first) group.push_back({gi[i].second}); // new group
      else group.back().push_back(gi[i].second); // same group
    }
    return group;
  }
public:
  TwoSat(int SZ):n(SZ){ // 点范围[0..SZ-1]
    low = vector<int>(2*n,-1);
    dfn = vector<int>(2*n,-1);
    stk = {};
    res = vector<int> (2*n,-1);
    p = vector<vector<int> >(2*n);
  }

  bool calc(vector<bool> & ans){
    auto group=sccgroup();
    vector<int> i2g(2*n);
    rep(i,0,group.size()) for(auto idx:group[i]) i2g[idx]=i;
    rep(i,0,n) if(i2g[i*2]==i2g[i*2+1])return false; // 同一个块的真假都在一个scc里
    vector<int> sccmutex(group.size()); // 互斥scc
    rep(i,0,n) { // 每个点的true/false 状态互斥,唯一, 因为建立边时的对称逻辑边
      sccmutex[i2g[i*2]] = i2g[i*2+1];
      sccmutex[i2g[i*2+1]] = i2g[i*2];
    }
    vector<vector<int> > G(group.size()); // 图
    vector<int> degree(group.size(),0);
    // 跨scc的反向边, 做拓扑选择, (因为scc计算后,剩下的一定是偏序不会有环)
    rep(i,0,2*n) for(auto j:p[i]) if(i2g[i]!=i2g[j]) G[i2g[j]].push_back(i2g[i]); // i -> j 反向边
    for(auto &s:G){// 去重
      sort(begin(s),end(s));
      s.resize(unique(begin(s),end(s))-begin(s));
    }
    for(auto &s:G) for(auto t:s) degree[t]++;
    vector<int> d0; // 入度为0
    rep(v,0,degree.size()) if(!degree[v]) d0.push_back(v);
    vector<int> sccpick(group.size(), -1); // scc -1未选, true选/false不选
    rep(i,0,d0.size()) {
      if(sccpick[d0[i]] == -1){ // 没有计算过
        // prinpick("pick %d, unpick %d\n",d0[i],sccmutex[d0[i]]);
        sccpick[d0[i]] = true;
        sccpick[sccmutex[d0[i]]] = false;
      }
      for(auto item:G[d0[i]]) if(!(--degree[item])) d0.push_back(item); // 更新入度排序
    }
    ans = vector<bool>(n);
    rep(i,0,n) ans[i] = sccpick[i2g[i*2+1]];
    return true;
  }
  void then(pair<int,bool> pi, pair<int,bool> pj){ // {i,true/false} -> {j,true/false}
    auto [i,bi] = pi;
    auto [j,bj] = pj;
    assert(i >= 0 && i < n);
    assert(j >= 0 && j < n);
    p[2*i+bi].push_back(2*j+bj);
    if(2*i+bi!=2*j+(!bj)) p[2*j+(!bj)].push_back(2*i+(!bi)); // 自动建立逻辑边
  }
};

// ---------------- lib ----------------

int main(){
  int n = read();
  int m = read(); // xi \in [0,m]
  int q = read();
  TwoSat ts(n*(m+1));
  auto _=[&](int i,int v){return i*(m+1)+v;}; // 编码 a[i] (>=v false, < v true)
  auto ge=[&](int i,int v){return pair<int,bool>{_(i,v),false};}; // greater equal than
  auto lt=[&](int i,int v){return pair<int,bool>{_(i,v),true};}; // less than
  auto chk=[&](int v){return 0<=v && v<=m;};
  rep(i,0,n) rep(v,1,m+1) ts.then(ge(i,v),ge(i,v-1)); // a[i]>=x 则 a[i] >= x-1 小于自动对称逻辑边
  // 不能 < 0, 所以建立 < 0 则 >= 0
  rep(i,0,n) ts.then(lt(i,0),ge(i,0));
  while(q--){
    int i=read()-1;
    int j=read()-1;
    int mn = read();
    int mx = read();
    // a[i]+a[j] >= x = mn, a[i] < v 则 a[j] >= x-v+1
    rep(v,0,m+1) if(chk(mn-v+1)) ts.then(lt(i,v),ge(j,mn-v+1)); // j到i 自动对称
    if(chk(mn-m)){ // mn-v+1 < 0的话 就是全部都可以 不需要建立失败逻辑, 而 a[j] >= x-v+1 > m 才需要
      int v=mn-m;
      ts.then(lt(i,v),ge(i,v));
      ts.then(lt(j,v),ge(j,v));
    }
    // a[i]+a[j] <= x = mx, a[i] >= v 则 aj < x-v+1
    rep(v,1,m+1) if(chk(mx-v+1)) ts.then(ge(i,v),lt(j,mx-v+1)); // j到i 自动对称
    if(chk(mx+1)){ // 同理 建立失败逻辑
      int v=mx+1;
      ts.then(ge(i,v),lt(i,v));
      ts.then(ge(j,v),lt(j,v));
    }
  }

  vector<bool> res= {};
  bool ok = ts.calc(res); // scc 联通分量 标识
  if(!ok){
    printf("-1\n");
    return 0;
  }
  rep(i,0,n) per(v,0,m+1) if(!res[_(i,v)]){ // a[i] >= v
    printf("%d ",v);// ans[i] = v;
    break;
  }
  return 0;
}


提出情報

提出日時
問題 Ex - Constrained Sums
ユーザ cromarmot
言語 C++ (GCC 9.2.1)
得点 600
コード長 4941 Byte
結果 AC
実行時間 1488 ms
メモリ 397348 KiB

コンパイルエラー

./Main.cpp: In function ‘int read()’:
./Main.cpp:5:23: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
    5 | int read(){int r;scanf("%d",&r);return r;}
      |                  ~~~~~^~~~~~~~~

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 600 / 600
結果
AC × 2
AC × 40
セット名 テストケース
Sample example0.txt, example1.txt
All example0.txt, example1.txt, handmade0.txt, handmade1.txt, random0.txt, random1.txt, random10.txt, random11.txt, random12.txt, random13.txt, random14.txt, random15.txt, random16.txt, random17.txt, random18.txt, random19.txt, random2.txt, random20.txt, random21.txt, random22.txt, random23.txt, random24.txt, random25.txt, random26.txt, random27.txt, random28.txt, random29.txt, random3.txt, random30.txt, random31.txt, random32.txt, random33.txt, random34.txt, random35.txt, random4.txt, random5.txt, random6.txt, random7.txt, random8.txt, random9.txt
ケース名 結果 実行時間 メモリ
example0.txt AC 5 ms 3748 KiB
example1.txt AC 2 ms 3688 KiB
handmade0.txt AC 2 ms 3784 KiB
handmade1.txt AC 2 ms 3764 KiB
random0.txt AC 1013 ms 302324 KiB
random1.txt AC 1051 ms 330148 KiB
random10.txt AC 913 ms 349824 KiB
random11.txt AC 796 ms 194900 KiB
random12.txt AC 1315 ms 378288 KiB
random13.txt AC 1422 ms 397348 KiB
random14.txt AC 492 ms 211188 KiB
random15.txt AC 489 ms 215524 KiB
random16.txt AC 924 ms 357168 KiB
random17.txt AC 653 ms 183500 KiB
random18.txt AC 1412 ms 381300 KiB
random19.txt AC 1488 ms 388884 KiB
random2.txt AC 484 ms 212224 KiB
random20.txt AC 492 ms 229128 KiB
random21.txt AC 470 ms 216160 KiB
random22.txt AC 961 ms 373372 KiB
random23.txt AC 703 ms 215260 KiB
random24.txt AC 1183 ms 383676 KiB
random25.txt AC 1152 ms 392356 KiB
random26.txt AC 474 ms 238548 KiB
random27.txt AC 500 ms 253264 KiB
random28.txt AC 802 ms 318480 KiB
random29.txt AC 1043 ms 371228 KiB
random3.txt AC 462 ms 202140 KiB
random30.txt AC 1052 ms 317344 KiB
random31.txt AC 1073 ms 326912 KiB
random32.txt AC 503 ms 206080 KiB
random33.txt AC 506 ms 208332 KiB
random34.txt AC 860 ms 329544 KiB
random35.txt AC 816 ms 217152 KiB
random4.txt AC 828 ms 326460 KiB
random5.txt AC 734 ms 190780 KiB
random6.txt AC 1115 ms 338792 KiB
random7.txt AC 1157 ms 347116 KiB
random8.txt AC 503 ms 221488 KiB
random9.txt AC 517 ms 232680 KiB