8.4日考试记录
今天题量挺大,没有在考试的时候写记录
而且做得也挺烂,所以仔细写一下记录
其实挺水一题。
其实我以前见过这道题目,做的时候直接开了个十六维数组233。
这道题的灵魂就是十六位的二进制。
但是考后随便动了动脑子,发现我恐怕是傻的真的菜
很明显,这个题目的操作就是按位异或,所以根本不需要花里胡哨乱七八糟的转变操作,
直接按环后移以为,异或一下就能够得出下一个状态
而因为只要出现循环,就会一直按照一个循环节绕下去,所以只要找循环节就OK了
然后我是真的服了我自己
根本没动脑子,以为循环节一定会包括第一个状态…
我现在真的不知道我当时到底什么状态犯这种错误
所以卡了我一个小时???
彻底重构代码三次???
其实第二题我也出现了这种问题,说明本次考试之中,我做题的思考太少了。
Think Twice,Code Once\color{red}\text{Think Twice,Code Once}Think Twice,Code Once
真理好吧
我喷我自己
Code:
#include<bits/stdc++.h>
using namespace std;
long long n,b,i,j,f[51][1<<16],a,cf=0;
int main(){
scanf("%lld%lld",&n,&b);
for (i=0;i<1<<n;i++)
for (j=0;j<n;j++)
f[0][i]+=((i&1<<(j+1)%n)>0^(i&1<<j)>0)*(1<<j);
for (i=1;i<=50;i++)
for (j=0;j<1<<n;j++)
f[i][j]=f[i-1][f[i-1][j]];
for (i=1;i<=n;i++){
scanf("%d",&a);
cf=cf<<1|a;
}
for(i=50;i>=0;i--)
if(1LL<<i<=b){
b-=1LL<<i;
cf=f[i][cf];
}
for (i=n-1;i>=0;i--)
printf("%lld\n",(cf&1<<i)>0);
return 0;
}
也不是很难的
但是也把我卡了很久,原因上面说了
一个很纯粹的模拟和离散化。
没有对头的咩咩不干扰答案,所以只要按照有对头咩咩的位置一个一个处理,用一个set判断就可以了
所以我还重构了一次代码???
真的是蠢哭了我去
Code:
#include<bits/stdc++.h>
using namespace std;
const int MAXK=1050;
int n,k,a,b,ans;
set <int> s;
struct node{
int sheep;
vector<int>hate;
}unfr[MAXK*2];
bool cmp(node x,node y){
return x.sheep<y.sheep;
}
int main(){
freopen("photo.in","r",stdin);
freopen("photo.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=0;i<k;i++){
scanf("%d%d",&a,&b);
unfr[i].sheep=min(a,b);
unfr[i].hate.push_back(max(a,b));
unfr[i+k].sheep=max(a,b);
}
sort(unfr,unfr+2*k,cmp);
for(int i=0;i<2*k;i++){
int siz=unfr[i].hate.size();
if(s.count(unfr[i].sheep))
ans++,s.clear();
for(int j=0;j<siz;j++)
s.insert(unfr[i].hate[j]);
}
printf("%d",ans+1);
return 0;
}
看起来好像就是一道裸的最短路
然后真的是的233
Dijkstra模板就过了
于是我还是没拿分???
本人Dijksta+heap优化,然后本地跑过。
测试…
Complie Error????
lock居然也是Bits的保留字我是真的…
心里一句MMP
将lock改了之后,测了还是没a
发现lock的位置又摆错了233
注意啊!!!
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,t,a,b,c,d[MAXN],loc[MAXN];
struct edge{
int from,to,value;
bool operator <(const edge &b) const{
return value>b.value;
}
}tmp,tmp233;
vector <edge> q[MAXN];
priority_queue <edge> Q;
void dijkstra(){
memset(d,0x3f,sizeof(d));
tmp.from=0,tmp.to=1,tmp.value=0;
Q.push(tmp),d[1]=0;
while(!Q.empty()){
tmp=Q.top(),Q.pop();
if(loc[tmp.to]) continue;
loc[tmp.to]=1;
int siz=q[tmp.to].size();
for(int i=0;i<siz;i++)
if(d[q[tmp.to][i].to]>d[tmp.to]+q[tmp.to][i].value){
tmp233=q[tmp.to][i];
d[q[tmp.to][i].to]=d[tmp.to]+q[tmp.to][i].value;
tmp233.value=d[q[tmp.to][i].to];
Q.push(tmp233);
}
}
}
int main(){
freopen("gohome.in","r",stdin);
freopen("gohome.out","w",stdout);
scanf("%d%d",&t,&n);
for(int i=0;i<t;i++){
scanf("%d%d%d",&a,&b,&c);
tmp.from=a,tmp.to=b,tmp.value=c;
q[a].push_back(tmp);
tmp.from=b,tmp.to=a;
q[b].push_back(tmp);
}
dijkstra();
printf("%d",d[n]);
return 0;
}
属于一道超出NOIP的难题(黑题233)
正解给的是状压DP,然后也写出了暴力搜索的优化方法作为标程。
Code(DP):
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define NMAX 12
#define infinite 1000000000
int dp[1 << NMAX];
int main() {
freopen("haywire.in","r",stdin);
freopen("haywire.out","w",stdout);
int n;
scanf("%d", &n);
int nbr[13][3];
for (int i = 0; i < n; i++) {
scanf("%d %d %d", &nbr[i][0], &nbr[i][1], &nbr[i][2]);
nbr[i][0]--; nbr[i][1]--; nbr[i][2]--;
}
dp[0] = 0;
for (int subset = 1; subset < (1 << n); subset++) {
int pending_links = 0;
for (int i = 0; i < n; i++) {//计算链出去的线
if (subset & (1<<i)) {
pending_links += 3-(((subset >> nbr[i][0]) & 1) +
((subset >> nbr[i][1]) & 1) +
((subset >> nbr[i][2]) & 1));
}
}
dp[subset] = infinite;
for (int i = 0; i < n; i++) {
if (subset & (1 << i)) {
int cost = pending_links - 3 + 2 * (((subset >> nbr[i][0]) & 1) +
((subset >> nbr[i][1]) & 1) +
((subset >> nbr[i][2]) & 1));
dp[subset] = min(dp[subset], dp[subset & ~(1<<i)] + cost);
}
}
}
printf("%d\n", dp[(1 << n) - 1]);
}
Code(暴力优化):
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define NMAX 12
#define infinite 1000000000
int dp[1 << NMAX];
int main() {
freopen("haywire.in","r",stdin);
freopen("haywire.out","w",stdout);
int n;
scanf("%d", &n);
int nbr[13][3];
for (int i = 0; i < n; i++) {
scanf("%d %d %d", &nbr[i][0], &nbr[i][1], &nbr[i][2]);
nbr[i][0]--; nbr[i][1]--; nbr[i][2]--;
}
dp[0] = 0;
for (int subset = 1; subset < (1 << n); subset++) {
int pending_links = 0;
for (int i = 0; i < n; i++) {//计算链出去的线
if (subset & (1<<i)) {
pending_links += 3-(((subset >> nbr[i][0]) & 1) +
((subset >> nbr[i][1]) & 1) +
((subset >> nbr[i][2]) & 1));
}
}
dp[subset] = infinite;
for (int i = 0; i < n; i++) {
if (subset & (1 << i)) {
int cost = pending_links - 3 + 2 * (((subset >> nbr[i][0]) & 1) +
((subset >> nbr[i][1]) & 1) +
((subset >> nbr[i][2]) & 1));
dp[subset] = min(dp[subset], dp[subset & ~(1<<i)] + cost);
}
}
}
printf("%d\n", dp[(1 << n) - 1]);
}
代码很长很长很长很长
我也不能完全理解233,只能按照自己去的梳理一下
由于这是一个排列类问题,所以直接来说本身并不很好转化为集合问题
但是发现:如果将确定了的兔子看做一个集合,那么这个集合往外延伸而耗费的电线其实和集合内的兔兔顺序无关
这就可以压缩成一个状态。
状态的设定呢?
也就是用01串表示这个兔子有没有在之前选过的这个集合里面
如果要往前推进,那么就要把下个兔兔放入集合中,这时就会有三个电线来源,一个是集合内的兔子连上新加入的,和没有连上但是需要延长的,还有就是加入的兔兔自己还要往外延的。
于是转移就是在加兔兔的时候,当前状态的集合删去一个兔兔的状态。加上一个电线数。
差不多就是这样
而暴力并不比dp容易理解一些,所以也不做赘述
主要是难得码字了233
但是确实,实现起来需要沉下心来想很久,现在也已经要下晚自习了,所以并不打算手打一遍
这次考试实在是考的瓜皮出一种境界了
仔细反省,码字之前的思考是真的不够缜密
但是其实平时的话我并不会这样,这两天考试的心态都有点过于急切了。
也有可能是没休息好没能静下心来吧
反正这都是问题,其实在算法层面,这些题目真的都没有什么可以说的,但是就是实现的时候写出的bug,映射了我自己打代码的时候的过于急躁