2020 ICPC 上海赛区

赛时6题。第七题我写的没de出来(给队友跪了)
xixike哥太强了有5题代码都是他写的(我只写了半题)
ggxxdd哥也非常强特别会数学题。
只有我什么都不会

G,B

都是队友切的签到,没看

M:

虽然会有重复的,但只要把前缀一起放到map里去就不会有任何重复的点因此可以打标记,这样就能建树了。然后就是dfs如果子树全被删除了该父节点就可以删除,否则就只能挨个删子节点。
我写了建树的部分,队友写的dfs

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
string s[105];
vector<int>E[10005];
int k;
bool vis[10005];
map<string,int>mp;
int ans=0;
int siz[N], num[N];
void dfs(int x){
// cout << "dfs " << x << endl;
if(vis[x]) num[x] = 1;
if(!E[x].size()) siz[x] = 1;
for(auto y : E[x]){
dfs(y);
siz[x] += siz[y], num[x] += num[y];
}
return;
}
inline void get_ans(int x){
// cout << "x " << x << " " << num[x] << " " << siz[x] << endl;
if(x > 1 && num[x] == siz[x]) return ans++, void();
for(auto y : E[x]) get_ans(y);
}
void solve(){
mp.clear();k=0,ans=0;
int n,m;cin>>n>>m;
for(int i = 1; i <= n + m; ++i) cin >> s[i];
// sort(s + 1, s + 1 + n + m);
// for(int i=1;i<=n;i++)cin>>s[i];
// for(int j=1;j<=m;j++)cin>>s[j+n];
mp["0"] = ++k;
for(int i=1;i<=n+m;i++){
string tmp="",s1="0";
for(int j=0;j<=(int)s[i].size();j++){
if(s[i][j]=='/'||j==s[i].size()){
string s2=s1;
if(!mp[s1]) mp[s1] = ++k;
s1 = s1 + '/' + tmp;
tmp="";
if(mp[s1] && mp[s2]) continue;
if(!mp[s1]) mp[s1]=++k;
// cout<<s1<<"\n";
E[mp[s2]].push_back(mp[s1]);
// cout << "add " << i << " " << j << " " << s2 << " " << s1 << endl;
if(j==s[i].size()&&i<=n)vis[mp[s1]]=1;
}
else{
tmp+=s[i][j];
}
}
}
dfs(1), get_ans(1);
cout<<ans<<"\n";
for(int i=1;i<=k;i++)E[i].clear(),vis[i]= num[i] = siz[i] = 0;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
int tt;cin>>tt;while(tt--){
solve();
}
}

D:

二分题。但是wa6,因为少考虑了第三种情况。。。

I:

考虑出在一个圆上应该如何走即可解决。

C:

据队友说是数位dp加上一些别的但是总之我不会

H:

赛时写完了没de完。思路队友切的。分为两段。
1.观察到把人和菜分别连线不会出现交叉的情况,所以可以枚举匹配
2.桌子最多只会调换一次方向

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e3 + 500;
int n, k, a[N], b[N],p2[N],p1[N];
int disr(int x,int y){
return (x-y+n)%n;
}
int disl(int x,int y){
return (y-x+n)%n;
}
bool cmp1(const int &x, const int &y) {
return disl(a[x],b[p1[x]])<disl(a[y],b[p1[y]]);
}
bool cmp2(int x,int y){
return disr(a[x],b[p1[x]])<disr(a[y],b[p1[y]]);
}
void solve() {
cin >> n >> k;
for (int i = 0; i < k; i++)cin >> a[i];
for (int i = 0; i < k; i++)cin >> b[i];
sort(a , a + k);
sort(b , b + k);
int ans=0x3f3f3f3f;
for(int j=0;j<k;j++)p2[j]=j;
for(int i=0;i<k;i++){
for(int j=0;j<k;j++){
p1[j]=(i+j)%k;
}
//left
sort(p2,p2+k,cmp1);
ans=min(ans,disl(a[p2[k-1]],b[p1[p2[k-1]]]));
int mx=0;
for(int j=k-2;j>=0;j--){
int pos=disl(a[p2[j]],b[p1[p2[j]]]);
mx=max(mx,disr(a[p2[j+1]],b[p1[p2[j+1]]]));
ans=min(ans,mx+pos*2);
}
//right
sort(p2,p2+k,cmp2);
ans=min(ans,disr(a[p2[k-1]],b[p1[p2[k-1]]]));
mx=0;
for(int j=k-2;j>=0;j--){
int pos=disr(a[p2[j]],b[p1[p2[j]]]);
mx=max(mx,disl(a[p2[j+1]],b[p1[p2[j+1]]]));
ans=min(ans,mx+pos*2);
}
}
cout<<ans<<endl;
}
int main() {
int t;
cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
}

E:

dp递推,每次最小的数必须放在前k个
如果能观察出1应该如何放的话其实不难想到怎么dp。。
式子需要稍微推一下就可以O(n)

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e7+10,mod=998244353;
int dp[maxn],inv[maxn];
void solve() {
int n,k;cin>>n>>k;
inv[0]=1;inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
int sum=1;
dp[0]=1;
for(int i=1;i<=n;i++){
dp[i]=sum*inv[i]%mod;
sum=(sum+dp[i])%mod;
if(i>=k)sum=(sum+mod-dp[i-k])%mod;
}
for(int i=2;i<=n;i++)dp[n]=dp[n]*i%mod;
cout<<dp[n]<<endl;
}
signed main() {
int t=1;
//cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
}

L:

其他题过的人没上百就不补了,收工

posted @   lyrrr  阅读(16)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示