Dashboard - 2023年中国大学生程序设计竞赛女生专场 - Codeforces
诈骗题 / 签到题。本来用排列组合算期望发现这个平局很奇妙,好像期望最大的就是m-1
个平局,一局决定胜负。
void solve() {
int n,m; cin>>n>>m;
cout<<"1/"<<n<<endl;
}
模拟 + 栈,根据题意进行模拟,注意移动时要把它上面的一起进行移动。写的复杂了
void solve() {
vector<vector<int>> ph(12);
ph[2].push_back(1); ph[3].push_back(2); ph[4].push_back(3);
vector<int> pos({0,2,3,4});
for(int i = 0; i < 12; ++i) {
int a,b; cin>>a>>b;
int ed = pos[a] + b;
int st = pos[a];
vector<int> tmp;
while(ph[st].size() && ph[st].back() != a) {
tmp.push_back(ph[st].back());
ph[st].pop_back();
}
if(ph[st].size() && ph[st].back() == a) {
tmp.push_back(ph[st].back());
ph[st].pop_back();
}
for(int j = tmp.size() - 1; j >= 0; --j) ph[ed].push_back(tmp[j]);
for(auto &t: ph[ed]) pos[t] = ed;
}
puts(ph[9].size() == 3 ? "Y" : "N");
}
n,m,k很小,爆搜重复太多会TLE,优化一下就可以过了,大概是排列搜索典题。
给属性分配任意的属性点,在满足属性点小于等于K
的情况下进行计算评分。
void solve() {
int n,m,k; cin>>n>>m>>k;
vector<array<int,7>> ask(m);
for(auto &t: ask) {
cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
}
vector<int> val(n + 1);
int ans = -1e18;
auto dfs = [&](auto &&self, int last, int from) -> void {
int mi = 0;
// 计算评分
for(auto &t: ask) {
int ai = val[t[0]], aj = val[t[1]];
int a = t[3], b = t[4], d = t[5], v = t[6];
if(t[2] == 1) {
if(ai * a + b * aj >= d) mi += v;
} else {
if(ai * a + b * aj <= d) mi += v;
}
}
ans = max(ans, mi);
if(last <= 0) return ;
for(int i = from; i <= n; ++i) {
if(val[i] >= k) continue;
last--;
val[i]++;
self(self, last, i);
last++;
val[i]--;
}
};
dfs(dfs,k * n, 1);
cout<<ans<<endl;
}
模拟 + 队列。主要是模拟,但是需要注意不同于我们一般认知的是:打完就换下一个。
例如,Apg先打,打完Apg跑到后面。到Bpg攻击时,攻击的是队列中的下一个,而不是那个攻击Bpg的PG。
之后就是模拟,使用技能攻击高的,如果有多个攻击高的,优先使用非终极技能。
我是这样模拟的:Apg先攻击Bpg,之后A攻击完后换其他的Apg。如果Bpg还有Hp就攻击那个新的Apg,否则Bpg换后面的攻击Apg。最后如果Bpg还有Hp放入队列后面;如果Apg还有Hp放到队列前面。
void solve() {
int n,m,k; cin>>n>>m>>k;
vector<array<int,8>> A(n),B(m);
deque<array<int,8>> Aq, Bq; // Hi, Ai, Bi, Ci, Di, Ei, Wi
for(auto &t: A) {
cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
Aq.push_back(t);
}
for(auto &t: B) {
cin>>t[0]>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
Bq.push_back(t);
}
for(int i = 0; i < k; ++i) {
auto Apg = Aq.front(), Bpg = Bq.front(); Aq.pop_front(); Bq.pop_front();
// Apgo对Bpgo的伤害
int phy = max(0LL, Apg[1] - Bpg[3]);
int mgc = max(0LL, Apg[2] - Bpg[4]);
int real = 0;
if(Apg[7] >= Apg[5]) real = Apg[6];
int ma = max(phy, mgc);
if(ma >= real) {
// 魔法 / 物理
Bpg[0] -= ma;
Apg[7]++;
} else {
Bpg[0] -= real;
Apg[7] -= Apg[5];
}
Aq.push_back(Apg);
Apg = Aq.front(); Aq.pop_front();
if(Bpg[0] > 0) {
phy = max(0LL, Bpg[1] - Apg[3]);
mgc = max(0LL, Bpg[2] - Apg[4]);
real = 0;
if(Bpg[7] >= Bpg[5]) real = Bpg[6];
ma = max(phy, mgc);
if(ma >= real) {
Apg[0] -= ma;
Bpg[7] ++;
} else {
Apg[0] -= real;
Bpg[7] -= Bpg[5];
}
} else {
// Bpg =
if(Bq.size() == 0) {
cout<<"Alice";
return;
}
Bpg = Bq.front(); Bq.pop_front();
phy = max(0LL, Bpg[1] - Apg[3]);
mgc = max(0LL, Bpg[2] - Apg[4]);
real = 0;
if(Bpg[7] >= Bpg[5]) real = Bpg[6];
ma = max(phy, mgc);
if(ma >= real) {
Apg[0] -= ma;
Bpg[7] ++;
} else {
Apg[0] -= real;
Bpg[7] -= Bpg[5];
}
}
if(Bpg[0] > 0) Bq.push_back(Bpg);
if(Apg[0] > 0) Aq.push_front(Apg);
if(Bq.size() == 0) {
cout<<"Alice";
return ;
}
if(Aq.size() == 0) {
cout<<"Bob";
return ;
}
}
cout<<"Draw";
}
构造。首先想到:后面比前面最多大1。
很像之前做过的拓扑序题,找一个满足条件的一个序列。但是对于用拓扑只有一点思路,没有找到切入点。
不过最长上升子序列。后面比前面的大,一定用到了前面的贡献,1 2 3 ... m
形如这样的可以用递增来填充。但是多个这个填充在给定条件中如果成立,则所有形如那样的序列分配都是合理的。
根据样例和自己造的数据发现:相同值对应元素按逆序填充是满足条件的。
in:
5
1 2 2 3 3
out: # 逆序
1 3 2 5 4
in:
4
1 2 1 2
out: # 逆序
2 4 1 3
void solve() {
int n; cin>>n;
vector<int> a(n + 1);
map<int,vector<int>> mp;
for(int i = 1; i <= n; ++i) cin>>a[i], mp[a[i]].push_back(i);
int ma = 0;
for(int i = 1; i <= n; ++i) {
if(a[i] > ma + 1) {
puts("-1");
return ;
}
ma = max(ma, a[i]);
}
vector<int> pos(n + 1);
int now = 1;
for(auto &t: mp) {
auto vec = t.vs;
for(int i = vec.size() - 1; i >= 0; --i) pos[vec[i]] = now++;
}
for(int i = 1; i <= n; ++i) cout<<pos[i]<<" ";
}