2020 ICPC Asia TW Site
本来只要写
C-Pyramid
因为初始状态是
然后只要求前
但是怎么算呢?
显然第奇数次经过的会往左边走,剩下的走右边。那么假设现在这个点有
然后从顶点往下递推就可以了。
把状态求出来,模拟第
查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n,k;
int a[50005005];
int calc(int i,int j){
return i*(i-1)/2+j;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
memset(a,0,sizeof(a));
cin>>n>>k;
a[1]=k-1;
for(int i=2;i<=n;++i){
for(int j=1;j<=i;++j){
if(j!=1)a[calc(i,j)]+=a[calc(i-1,j-1)]/2;
if(j!=i)a[calc(i,j)]+=(a[calc(i-1,j)]+1)/2;
}
}
int i=1,j=1;
while(1){
if(i==n){
cout<<j-1<<'\n';
break;
}
if(a[calc(i,j)]%2==1)++j;
++i;
}
}
return 0;
}
这个是
E-A Color Game
看到这个题想到了小学时某年寒假一些不好的回忆
首先可以看出这是个区间 dp。
状态比较特殊:
枚举区间长、起点、断点的元素类型后,方程如下:
查看代码
if(dp[i][k][c]&&dp[k+1][j][c]){
dp[i][j][c]=max(dp[i][j][c],dp[i][k][c]+dp[k+1][j][c]);
}
if(dp[i][k][c]&&dp[k+1][j][c]&&dp[i][k][c]+dp[k+1][j][c]>=m){
flg[i][j]=1;
}
if(flg[i][k]){
dp[i][j][c]=max(dp[i][j][c],dp[k+1][j][c]);
}
if(flg[k+1][j]){
dp[i][j][c]=max(dp[i][j][c],dp[i][k][c]);
}
就没事了!
F-Cable Protection
基环树上 dp!
首先考虑如果是树怎么办。
考虑树形 dp,设
然后只要随机在环里面断开一条边,以两边分别为根节点跑 dp 并取最小值即可。
点击查看代码
#include<bits/stdc++.h>
//#define int long long
using namespace std;
int n,m,dp[2000005][2],x,y;
vector<int>nbr[2000005];
void dfs(int cur,int fa){
dp[cur][1]=dp[cur][0]=0;
// if(nbr[cur].size()==1&&nbr[cur][0]==fa)dp[cur][0]=1e9;
for(auto to:nbr[cur]){
if(to==fa)continue;
dfs(to,cur);
dp[cur][0]+=dp[to][1];
dp[cur][1]+=min(dp[to][0],dp[to][1]);
}
dp[cur][1]++;
return;
}
signed main(){
// freopen("F2.in","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
bool flg=0;
for(int i=0;i<n+m;++i){
int u,v;
cin>>u>>v;
if(!flg&&u<n&&v<n){
flg=1;
x=u,y=v;
continue;
}
nbr[u].push_back(v);
nbr[v].push_back(u);
}
dfs(x,-1);
int ans=dp[x][1];
memset(dp,0,sizeof(dp));
dfs(y,-1);
ans=min(ans,dp[y][1]);
cout<<ans;
return 0;
}
H-Optimization for UltraNet
要求最小边最大,最大生成树!
要求边权和最小,最小生成树!
怎么结合上面这俩呢?
因为第一个条件更加优先,先跑最大生成树!
找到最小的一条边,把边权大于这个的边再跑一次最小生成树就可以了!
然后按边权从大到小用并查集合并,贡献就是并查集两端的
查看代码
#include<bits/stdc++.h>
//#define int long long
using namespace std;
int n,m,dp[2000005][2],x,y;
vector<int>nbr[2000005];
void dfs(int cur,int fa){
dp[cur][1]=dp[cur][0]=0;
// if(nbr[cur].size()==1&&nbr[cur][0]==fa)dp[cur][0]=1e9;
for(auto to:nbr[cur]){
if(to==fa)continue;
dfs(to,cur);
dp[cur][0]+=dp[to][1];
dp[cur][1]+=min(dp[to][0],dp[to][1]);
}
dp[cur][1]++;
return;
}
signed main(){
// freopen("F2.in","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
bool flg=0;
for(int i=0;i<n+m;++i){
int u,v;
cin>>u>>v;
if(!flg&&u<n&&v<n){
flg=1;
x=u,y=v;
continue;
}
nbr[u].push_back(v);
nbr[v].push_back(u);
}
dfs(x,-1);
int ans=dp[x][1];
// for(int i=0;i<n+m;++i)cout<<"Test: "<<dp[i][0]<<' '<<dp[i][1]<<'\n';
memset(dp,0,sizeof(dp));
dfs(y,-1);
ans=min(ans,dp[y][1]);
cout<<ans;
return 0;
}
K-Number with Bachelors
神秘数位 dp。
学习到的东西:输入 hex
,换回 dec
!
然后直接用搜索写数位 dp 即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ull=unsigned long long;
#define int long long
//#pragma GGC optimize(2)
int n,a[18];
ull dp[2][18][2<<17];
//位数 状压每个数是否出现 到没到上线 是否有前导0 10 or 16进制
ull dfs(int tot,int st,bool lim,bool flg,bool base){
if(!tot)return 1;
if(flg&&lim&&dp[base][tot][st]!=1e18+1)return dp[base][tot][st];
int x=(lim?(base?15:9):a[tot]);
ull ans=0;
for(int i=0;i<=x;++i){
if(!i){
if(flg){
if(st>>i&1)continue;
ans+=dfs(tot-1,st^(1<<i),lim||(i<x),flg||(i!=0),base);
}
else{
ans+=dfs(tot-1,st,lim||(i<x),flg||(i!=0),base);
}
}
else{
if(st>>i&1)continue;
ans+=dfs(tot-1,st^(1<<i),lim||(i<x),flg||(i!=0),base);
}
}
// cout<<tot<<" "<<st<<" ans = "<<ans<<endl;
if(flg&&lim)dp[base][tot][st]=ans;
return ans;
}
ull calc_10(ull x){
int tot=0;
while(x){
a[++tot]=x%10;
x/=10;
}
return dfs(tot,0,0,0,0);
}
ull calc_16(ull x){
int tot=0;
while(x){
a[++tot]=x%16;
x/=16;
}
return dfs(tot,0,0,0,1);
}
void work_10(){
int opt;
cin>>dec>>opt;
if(opt==0){
ull a,b;
cin>>dec>>a>>dec>>b;
if(a>1e9)a=1e9;
if(b>1e9)b=1e9;
// cout<<"Hello"<<endl;
if(a==0)cout<<dec<<calc_10(b)<<'\n';
else cout<<dec<<calc_10(b)-calc_10(a-1)<<'\n';
}
else{
ull x;
cin>>dec>>x;
int lt=-1,rt=1e9+1;
while(lt+1<rt){
int mid=lt+rt>>1;
if(calc_10(mid)<x)lt=mid;
else{
rt=mid;
if(mid==0)break;
}
}
if(rt==1e9+1)cout<<"-\n";
else cout<<dec<<rt<<'\n';
}
}
void work_16(){
int opt;
cin>>dec>>opt;
if(opt==0){
ull a,b;
cin>>hex>>a>>hex>>b;
if(a==0)cout<<hex<<calc_16(b)<<'\n';
else cout<<hex<<calc_16(b)-calc_16(a-1)<<'\n';
}
else{
ull x;
cin>>hex>>x;
int lt=-1,rt=1e9+1;
while(lt+1<rt){
int mid=lt+rt>>1;
if(calc_16(mid)<x)lt=mid;
else{
rt=mid;
if(!mid)break;
}
}
if(rt==1e9+1)cout<<"-\n";
else cout<<hex<<rt<<'\n';
}
}
signed main(){
for(int i=0;i<=1;++i)for(int j=0;j<=17;++j)for(int k=0;k<(2<<17);++k)dp[i][j][k]=1e18+1;
cin>>n;
for(int i=1;i<=n;++i){
char c;
cin>>c;
if(c=='d')work_10();
else work_16();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!