pyyzDay14
模拟赛(不错?)
T1 Segments Removal
双向链表考虑合并
注意到堆中记录区间长度和id
一个升序一个降序不好维护
于是倒序输入
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[200005],pre[200005],nxt[200005],col[200005],siz[200005],cnt,vis[200005];
priority_queue<pair<int,int> > hp;
signed main() {
// freopen("remove.in","r",stdin);
// freopen("remove.out","w",stdout);
int n;
cin>>n;
for(int i=n;i;i--) cin>>a[i];
for(int i=1;i<=n;i++){
if(a[i]==a[i-1]) siz[cnt]++;
else{
col[++cnt]=a[i];
siz[cnt]=1;
}
}
for(int i=1;i<=cnt;i++){
pre[i]=i-1;
nxt[i]=i+1;
hp.push({siz[i],i});
}
int ans=0;
while(!hp.empty()){
int c=hp.top().second;
hp.pop();
if(vis[c]) continue;
ans++;
int l=pre[c],r=nxt[c];
pre[r]=l;
nxt[l]=r;
vis[c]=1;
if(col[l]==col[r]&&r<=n&&l>=1){
nxt[pre[l]]=r;
pre[r]=pre[l];
vis[l]=1;
siz[r]+=siz[l];
hp.push({siz[r],r});
}
}
cout<<ans<<'\n';
return 0;
}
T2 [USACO23OPEN] FEB B
赛时切!
大分讨(对着暴力猜结论)
找F连续段,分长度奇偶/两端是否相等分别计算即可
发现答案是公差为1/2的等差数列
计算出首项min末项max就知道了整个数列
#include<bits/stdc++.h>
using namespace std;
#define int long long
set<int> ans;
string s;
int n;
int l[20];
void dfs(int x){
if(x==n){
int sum=0;
string q=s;
for(int i=1;i<=n;i++){
if(l[i]&&q[i-1]=='F') q[i-1]='E';
else if(!l[i]&&q[i-1]=='F') q[i-1]='B';
}
for(int i=0;i<n;i++){
if(q[i]==q[i+1]) sum++;
}
ans.insert(sum);
return ;
}
x++;
dfs(x);
l[x]=1;
dfs(x);
l[x]=0;
}
signed main() {
// freopen("string.in","r",stdin);
// freopen("string.out","w",stdout);
cin>>n;
cin>>s;
if(n<=10){
dfs(0);
cout<<ans.size()<<'\n';
for(auto ed:ans){
cout<<ed<<'\n';
}
return 0;
}
int an=0;
for(int i=1;i<n-1;i++){
if(s[i]=='F'&&s[i-1]=='B'&&s[i+1]=='E') s[i]='B';
else if(s[i]=='F'&&s[i+1]=='B'&&s[i-1]=='E') s[i]='B';
else if(s[i]=='F'&&s[i-1]!='F'&&s[i+1]!='F') an++;
}
int len=0,minn=0,anss=0;
for(int i=0;i<n;i++){
if(s[i]=='F'&&s[i+1]=='F'){
int j=i+1;
int ll=1;
while(s[j]=='F'&&j<n){
j++;
ll++;
}
if(!i||j>=n||s[i-1]!=s[j]){
if(!i&&j>=n) ll--;
if(i&&j<n&&ll%2==1) minn++;
}
else{
if(ll%2==0) minn++;
ll++;
}
i=j;
len+=ll;
}
}
for(int i=0;i<n;i++){
if(s[i]==s[i+1]&&s[i]!='F') anss++;
}
int st=anss+minn,en=anss+len+2*an;
if(s[0]=='F'||s[n-1]=='F'){
if(s[0]=='F'&&s[1]!='F') en++;
if(s[n-1]=='F'&&s[n-2]!='F') en++;
cout<<en-st+1<<'\n';
for(int i=st;i<=en;i++) cout<<i<<'\n';
}
else{
cout<<(en-st)/2+1<<'\n';
for(int i=st;i<=en;i+=2) cout<<i<<'\n';
}
return 0;
}
T3 [SDOI2016] 齿轮
大法师!
数据范围较小
对每个点进行图遍历
看是否会卡住
注意除法精度问题(不要像我一样赛时不开double)
#include<bits/stdc++.h>
using namespace std;
const long double eps=1e-10;
vector<pair<int,pair<long double,long double> > > tu[1005];
int n,m,ff,vis[1005];
long double lin[1005];
void dfs(int x,long double sum){
if(vis[x]){
if(fabs(lin[x]-sum)>eps) ff=1;
return ;
}
vis[x]=1;
lin[x]=sum;
for(auto ed:tu[x]){
long double gx=ed.second.first;
long double gy=ed.second.second;
dfs(ed.first,sum*gx/gy);
}
}
void solve(int bianhao){
memset(lin,0,sizeof(lin));
memset(vis,0,sizeof(vis));
cin>>n>>m;
for(int i=1;i<=n;i++){
tu[i].clear();
}
for(int i=1;i<=m;i++){
int l,r;
long double x,y;
cin>>l>>r>>x>>y;
tu[l].push_back({r,{x,y}});
tu[r].push_back({l,{y,x}});
}
ff=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(i,1.0);
}
if(ff) break;
}
if(ff) cout<<"Case #"<<bianhao<<": No"<<'\n';
else cout<<"Case #"<<bianhao<<": Yes"<<'\n';
}
signed main() {
//freopen("gear.in","r",stdin);
//freopen("gear.out","w",stdout);
int T;
cin>>T;
for(int i=1;i<=T;i++){
solve(i);
}
return 0;
}
也可记录每个x,y,约分,防止失精
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<pair<int,pair<int,int> > > tu[1005];
int n,m,ff,vis[1005],suma[1005],sumb[1005];
void dfs(int x,int sua,int sub){
if(vis[x]){
if(suma[x]*sub!=sumb[x]*sua) ff=1;
return ;
}
vis[x]=1;
suma[x]=sua;
sumb[x]=sub;
int gg=__gcd(abs(suma[x]),abs(sumb[x]));
suma[x]/=gg;
sumb[x]/=gg;
for(auto ed:tu[x]){
int gx=ed.second.first;
int gy=ed.second.second;
gx*=sua;
gy*=sub;
int g=__gcd(abs(gx),abs(gy));
gx/=g;
gy/=g;
dfs(ed.first,gx,gy);
if(ff) return ;
}
}
void solve(int bianhao){
memset(suma,0,sizeof(suma));
memset(sumb,0,sizeof(sumb));
memset(vis,0,sizeof(vis));
cin>>n>>m;
for(int i=1;i<=n;i++){
tu[i].clear();
}
for(int i=1;i<=m;i++){
int l,r;
int x,y;
cin>>l>>r>>x>>y;
tu[l].push_back({r,{x,y}});
tu[r].push_back({l,{y,x}});
}
ff=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(i,1,1);
}
if(ff) break;
}
if(ff) cout<<"Case #"<<bianhao<<": No"<<'\n';
else cout<<"Case #"<<bianhao<<": Yes"<<'\n';
}
signed main() {
//freopen("gear.in","r",stdin);
//freopen("gear.out","w",stdout);
int T;
cin>>T;
for(int i=1;i<=T;i++){
solve(i);
}
return 0;
}
T4 [POI 2010] GRA-The Minima Game
博弈论DP
发现每个数的顺序和个数不重要
排序去重
设dp_i表示考虑1~i先手的最大优势
考虑枚举j,表示一次拿走j+1~i
则dp_i=max(dp_i,a_(j+1)-dp_j)
发现dp_i在不断更新
dp_i存储i以前的最大的a_(j+1)-dp_j
所以转移方程只需O(n)枚举i
dp_i=max(dp_(i-1),a_i-dp_(i-1))
即只考虑是否只选i
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[1000005],dp[1000005];
signed main() {
// freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int len=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=len;i++){
dp[i]=max(dp[i-1],a[i]-dp[i-1]);
}
cout<<dp[len]<<'\n';
return 0;
}

浙公网安备 33010602011771号