2020ICPC上海区域赛部分补题
B 思维
需要靠灵机一动的一道思维,不太聪明的本思维苦手还在一个个凑…
发现性质:一张图雷和空地逆转后,空地的数字不变,因为相邻雷和空地是两两一对
又发现从B图变到A图和A的逆转图的操作次数和是n*m
const int N=1e3+10,mod=1e9+9;
int n,m;
string a[N],b[N],ia[N];
map<char,char>cg={{'.','X'},{'X','.'}};
void printmap(string s[]){forr(i,0,n-1){cout<<s[i]<<endl;}
}
void solve(){//B: 结果相同B->A//发现神奇性质 A图全反转后和原来的图结果一样 B到A/inv(A)的修改ans1+ans2=n*m 中总有一个相差<nm/2的cin>>n>>m;forr(i,0,n-1)cin>>a[i];forr(i,0,n-1)cin>>b[i];forr(i,0,n-1){forr(j,0,m-1)ia[i]+=cg[a[i][j]];}int ans1,ans2;ans1=ans2=0;forr(i,0,n-1){forr(j,0,m-1){ans1+=(a[i][j]!=b[i][j]);ans2+=(ia[i][j]!=b[i][j]);}}if(ans1<ans2){printmap(a);}else printmap(ia);
}
M DFS
发现文件夹是一个树状结构,把不用ignore的路径都标记,说明不能一股脑git文件夹,还得下一层找。
const int N=1e3+10,mod=1e9+9;
int n,m;
unordered_map<string,set<string>>tr;
unordered_map<string,int>st;
void op(string s,int fg){//处理路径string pre="A",now;char tag='0';//层数标记 防止路径上的文件夹重名for(auto x:s){if(x=='/'){st[pre]=fg;now+=(tag++);tr[pre].insert(now);pre=now;}now+=x;}string nowf='F'+now+tag;//文件打上标记和路径上的文件夹区分st[pre]=st[nowf]=fg;tr[pre].insert(nowf);
}
int dfs(string now){// cout<<now<<' '<<st[now]<<endl;if(st[now]==0)return 1;//只需要一次查找else if(now[0]=='F')return 0;//到文件了int ret=0;for(auto x:tr[now]){int xret=dfs(x);ret+=xret;}return ret;
}
void solve(){//Gtr.clear();st.clear();cin>>n>>m;forr(i,1,n){string ig;cin>>ig;op(ig,0);}forr(i,1,m){string nig;cin>>nig;op(nig,1);}st["A"]=1;//根 必须向下遍历cout<<dfs("A")<<endl;
}
D 三分 贪心
double n,p1,v1,p2,v2;
/* 废片 没用三分 两点向两边走再向中间汇总
double ans1(){double ans=0;double t1=p1/v1,t2=(n-p2)/v2;ans+=max(t1,t2);if(t1<t2){double dt=t2-t1,tp1=dt*v1;ans+=(n-dt)/(v1+v2);}else{double dt=t1-t2,tp2=n-dt*v2;ans+=tp2/(v1+v2);}return ans;
}
*/
//三分中间汇总的距离 取到最小时间
double ans2(){double ans=1e18;double l=p1,r=p2;auto cal=[](double x)->double{double t1=(x+min(p1,x-p1))/v1,t2=(n-x+min(p2-x,n-p2))/v2;return max(t1,t2);};while (r-l>1e-10){double mid1=l+(r-l)/3,mid2=r-(r-l)/3;double tm1=cal(mid1),tm2=cal(mid2);ans=min({ans,tm1,tm2});if(tm1<tm2){r=mid2;}else{l=mid1;}}return ans;
}
//特殊情况
double ans3(){double a3=max((n-p1)/v1,p2/v2);//对冲//一个人走 double a1=(min(p1,n-p1)+n)/v1;double a2=(min(p2,n-p2)+n)/v2;return min({a1,a2,a3});
}
void solve(){cin>>n>>p1>>v1>>p2>>v2;cout<<fixed<<setprecision(10);/* 这里wa13 两人同位置不一定向两边走,也可能一人走得飞快把路都走完if(p1==p2){cout<<n/(v1+v2)<<endl;return;}*/if(p1>p2){swap(p1,p2);swap(v1,v2);}// cout<<ans1()<<' '<<ans2()<<' '<<ans3()<<endl;cout<<min({ans2(),ans3()})<<endl;
}
I dp
O(1)做法好烧脑,只学习了O(n)做法,对我来说也很难想到…
dalao题解
const double pi=acos(-1);
void solve(){int n,m;cin>>n>>m;//O(n)做法//每个点到其他点的距离都一样 只求一个点就可以 分同层和异层去求vector<double>dp(n+1,0),g(n+1,0);//dp[i] 外层一点 到其他所有点距离forr(i,1,m-1){g[1]+=min(2.0,i*pi/(m*1.0));//一个点到同层其他点}g[1]*=2;//对称g[1]+=2;//对称轴上的直边dp[1]=g[1];forr(i,2,n){g[i]=i*g[1];dp[i]=dp[i-1]+g[i]+(i-1)*2.0*m;//dp[i-1]:异层 g[i]同层 (i-1)*2m到第一层的直边:两图中发现想要换到其他角度,走最内层或内层直边最近}double ans=0;forr(i,1,n){//异层 + 同层(两两组合会重复,去掉一个g[i]) + 到中心ans+=2.0*m*(dp[i]-g[i])+1.0*m*g[i]+(m==1?0:i*2.0*m);//m=1时 g[1]中已经算过每个点到中心的边}cout<<fixed<<setprecision(8)<<ans<<endl;
}
C 二进制数位dp
dalao题解
分析原式子
∑i=0X∑j=[i=0]Y[i&j=0]⌊log2(i+j)+1⌋\sum_{i=0}^{X}\sum_{j=[i=0]}^{Y}[i\&j=0]\lfloor\log_2(i+j)+1\rfloor∑i=0X∑j=[i=0]Y[i&j=0]⌊log2(i+j)+1⌋
- i&j=0i\&j=0i&j=0,i j每一位相与=0才有贡献
- ⌊log2(i+j)+1⌋\lfloor\log_2(i+j)+1\rfloor⌊log2(i+j)+1⌋是(i+j)的二进制最高1的位置
枚举i,j的每一位二进制,计算符合i&j=0i\&j=0i&j=0的(i,j)个数
const int N=100,mod=1e9+7,inf=1e9+10;
int a[N],b[N],dp[N][2][2];
//二进制数位dp
int dfs(int pos,int limit1,int limit2){if(pos==0)return 1;if(~dp[pos][limit1][limit2])return dp[pos][limit1][limit2];int up1=(limit1?a[pos]:1);int up2=(limit2?b[pos]:1);int res=0;forr(i,0,up1){forr(j,0,up2){if((i&j)==0){res+=dfs(pos-1,limit1&&up1==i,limit2&&up2==j);res%=mod;}}}return dp[pos][limit1][limit2]=res;
}
void solve(){memset(a,0,sizeof a);memset(b,0,sizeof b);memset(dp,-1,sizeof dp);int x,y;cin>>x>>y;int cnt1,cnt2;cnt1=cnt2=0;while (x){a[++cnt1]=x%2;x/=2;}while (y){b[++cnt2]=y%2;y/=2;}int len=max(cnt1,cnt2),ans=0;forr(l,1,len){//枚举位数int cnt=0;//答案种数计数//最高位为L 意味着i或j有一个数这一位是1//但是i&j=0只有一个数高位是1if(l<=cnt1){//i的高位1cnt+=dfs(l-1,l==cnt1,l>cnt2);}if(l<=cnt2){//j的高位是1cnt+=dfs(l-1,l>cnt1,l==cnt2);}ans=(ans+cnt*l%mod)%mod;//计算贡献}cout<<ans<<endl;
}