星期一:
下午洛谷训练赛
补俩题:
思路:计算u到v的路径数,以及路径上每个点的遍历次数,遍历次数等于路径总数即为关键点
代码如下:
ll n;
int m,u,v;
vector<int>ve[1010],pa;
int cnt[1010];
bool vi[1010];
ll sum,ans;
void dfs(int x){
if(x==v){
sum++;
for(auto i:pa) cnt[i]++;
return ;
}
for(auto i:ve[x]){
if(!vi[i]){
vi[i]=1,pa.push_back(i);
dfs(i);
vi[i]=0,pa.pop_back();
}
}
}
void solve(){
cin >> n >> m;
for(int i=1;i<=m;i++){
int u,v;
cin >> u >> v;
ve[u].push_back(v);
ve[v].push_back(u);
}
cin >> u >> v;
dfs(u);
if(sum>0){
for(int i=1;i<=n;i++)
if(cnt[i]==sum) ans++;
cout << ans-1;
}else cout << "-1";
return ;
}
数正方形:
思路:一个长度为k的框,正方形顶点全在框上的情况有k种, 长度为n的大框,包含长为i的小框有 (n-i+1)^2个
代码如下:
ll n;
ll ans;
void solve(){
cin >> n;n--;
for(int i=1;i<=n;i++) ans=(ans+(n-i+1)*(n-i+1)*i)%mod;
cout << ans;
}
星期二:
打了cf round929 div3, a-e题都很简单,手速还行
星期三:
pta上的训练赛,怎么全是模拟啊
星期四:
入门状压dp (小国王)(洛谷P1896)传送门
代码如下:
int n;
int k,cnt;
int s[1<<12],num[1<<12];
ll dp[12][144][1<<12];
void solve(){
cin >> n >> k;
for(int i=0;i<(1<<n);i++){
if(!(i&i<<1)){
s[cnt++]=i; //不要用++cnt
for(int j=0;j<n;j++) num[i]+=(i>>j&1);
}
}
dp[0][0][0]=1;
for(int i=1;i<=n+1;i++){
for(int j=0;j<=k;j++){
for(int a=0;a<cnt;a++){
for(int b=0;b<cnt;b++){
int c=num[s[a]];
if(j<c || s[a]&s[b] || s[a]&(s[b]<<1) || s[a]&(s[b]>>1)) continue;
dp[i][j][a]+=dp[i-1][j-c][b];
}
}
}
}
cout << dp[n+1][k][0];
}
晚上cf睡过头了, 醒来34分, 脑袋迷糊没敢入场,a,b写了后发现C是道交互, 还好
星期五:
cf round931 div2的C又是交互,做不来,还好前俩题手速够快
星期六:
发车2min前上火车,刺激
前所未有的高度,开心
状压dp,玉米田 b站传送门
代码如下:
ll n;
int m;
int s[1<<14],g[14],cnt;
ll dp[20][1<<14];
void solve(){
cin >> n >> m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x; cin >> x;
g[i]=(g[i]<<1)+x;
}
}
for(int i=0;i<(1<<m);i++){
if(!(i&(i<<1))) s[cnt++]=i;
}
dp[0][0]=1;
for(int i=1;i<=n+1;i++){
for(int a=0;a<cnt;a++){
for(int b=0;b<cnt;b++)
if((s[a]&g[i])==s[a] && !(s[a]&s[b])) dp[i][a]+=dp[i-1][b];
}
}
cout << dp[n+1][0];
}
周日:
状压dp 炮兵部队 洛谷传送门
代码如下:
ll n;
int m;
int g[110],s[1<<12],cnt,num[1<<12];
ll dp[2][1<<12][1<<12]; //滚动
void solve(){
cin >> n >> m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char x; cin >> x;
if(x=='P') x='1';
else x='0';
g[i]=(g[i]<<1)+x-'0';
}
}
for(int i=0;i<(1<<m);i++){
if(!(i&i<<1) && !(i&i<<2)){
s[cnt++]=i;
for(int j=0;j<m;j++) num[i]+=(i>>j&1);
}
}
for(int i=1;i<=n+2;i++){
for(int a=0;a<cnt;a++){
for(int b=0;b<cnt;b++){
for(int c=0;c<cnt;c++){
int d=num[s[a]];
if((s[a]&g[i])!=s[a] || (s[b]&g[i-1])!=s[b]
|| s[a]&s[b] || s[a]&s[c] || s[b]&s[c]) continue;
dp[i&1][b][a]=max(dp[i-1&1][c][b]+d,dp[i&1][b][a]);
}
}
}
}
cout << dp[n+2&1][0][0];
}
状压dp 国际象棋 洛谷传送门
代码如下:
ll n;
int m,k;
int num[1<<6];
ll dp[110][30][1<<6][1<<6]; //开1<<8会mle
void solve(){
cin >> m >> n >> k;
for(int i=0;i<(1<<m);i++){
for(int j=0;j<m;j++) num[i]+=(i>>j&1); //单行内所有状态合法
}
dp[0][0][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=k;j++){
for(int a=0;a<(1<<m);a++){
for(int b=0;b<(1<<m);b++){
for(int c=0;c<(1<<m);c++){
int d=num[a];
if(j<d || a&b<<2 || a&b>>2 || a&c<<1 || a&c>>1
|| b&c<<2 || b&c>>2) continue;
dp[i][j][b][a]=(dp[i][j][b][a]+dp[i-1][j-d][c][b])%mod;
}
}
}
}
}
ll ans=0;
for(int i=0;i<(1<<m);i++){
for(int j=0;j<(1<<m);j++)
ans=(ans+dp[n][k][i][j])%mod;
}
cout << ans;
// cout << dp[n+2][k][0][0]; //因为mle所以开不了n+2
}
cf round931 div2 C题(交互 找矿
思路:先问三个边角,得到三条线的范围,两个交点中必含一矿
代码如下:
ll n;
int m;
int ask(int x,int y){
cout << "? " << x << " " << y << endl;
int res; cin >> res;
return res;
}
void solve(){
cin >> n >> m;
int a=ask(1,1);
int b=ask(n,1);
int c=ask(1,m);
int x1=(a-b+n+1)/2,y1=(a+b-n+3)/2;
int x2=(a+c-m+3)/2,y2=(a-c+m+1)/2;
if(x1>=1 && x1<=n && y1>=1 && y1<=m && !ask(x1,y1)){
cout << "! " << x1 << " " << y1 << endl;
}else{
cout << "! " << x2 << " " << y2 << endl;
}
}
如最后的判断写成这样就会wa:(但尚不知晓原因)
if(x1>=1 && x1<=n && y1>=1 && y1<=m && ask(x1,y1)){
cout << "! " << x2 << " " << y2 << endl;
}else{
cout << "! " << x1 << " " << y1 << endl;
}