翡翠的排挤原理
【前言】
一些以宝石命名的书籍,拥有神奇的能力,乃魔法之书.
魔法之书会自动挑选附近有意志讲述故事的人作为原著的表演者,在现实中
演绎故事,只有当故事迎来结尾,魔法之书才会合上.
时至今日,故事仍在不停地打开......
【问题描述】
少年注意到了一个少女.
少女总是孤身一人,受人冷落.不知从何时开始,不幸的魔法使,人们这样称呼
她.
少女总是在少年面前遭遇不幸:走路差点被车撞;被不知名的罪犯在桌子上乱
刻;下楼梯被看不见的凶手推下楼......
少年开始帮少女调查凶手,却找不到任何线索.在寻找的途中,少年和少女相恋
了,少女不再孤身一人.
调查仍在继续.少年又发现了一样少女被破坏的东西,那是一张纸,纸上似乎曾
写着N 个数,而现在,每个数都被破坏得只剩下了一个数字.
这曾是一个非负整数的等差数列,公差也非负.这N 个数字分别是等差数列每
个数字的其中一位,并且都是同一位.在序列旁,犯罪者如此宣称到.
看着清秀的字迹,少年若有所思.
少年决定先将故事还原,再揭开故事的谜底.
让一切都重新开始吧.
(注:一个数字的位指的是这个数字从低到高数上来的数字,且位数不足用0补
齐.如102的第一位是2,第二位是0,第三位是1,第四位是0.)
【输入格式】
从文件 emerald.in 中读入数据。
一行一个长度为N 的字符串描述这个剩余的这个串.【输出格式】
输出到文件 emerald.out 中。
一行输出该等差数列的首项.如果有多个首项满足条件,则输出最小的首项.如
果没有首项,就输出−1.
【样例输入1】
6925814703
【样例输出1】
6
【样例解释】
取A i = 6 + 3 * i,保留该等差数列的第一位即为答案.
【数据规模】
对于10%的数据:N ≤ 10.
对于30%的数据:N ≤ 100.
对于50%的数据:N ≤ 1000
对于70%的数据:N ≤ 7000
对于100%的数据:N ≤ 10000.
1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include<map> 12 #define eps 1e-9 13 #define For(i,a,b) for(int i=(a);i<=(b);i++) 14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 15 const int N=10007; 16 typedef long long LL; 17 typedef double db; 18 using namespace std; 19 int n,q[N],p[N]; 20 char s[N]; 21 db l,r; 22 23 template<typename T> void read(T &x) { 24 char ch=getchar(); x=0; T f=1; 25 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 26 if(ch=='-') f=-1,ch=getchar(); 27 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 28 } 29 30 #define DEBUG 31 int main() { 32 #ifdef DEBUG 33 freopen("emerald.in","r",stdin); 34 freopen("emerald.out","w",stdout); 35 #endif 36 scanf("%s",s); 37 n=strlen(s); 38 int tp=s[1]-s[0]<0?s[1]-s[0]+10:s[1]-s[0]; 39 int mx=tp,mi=tp; 40 For(i,1,n-1) { 41 int x1=s[i]-'0',x2=s[i-1]-'0'; 42 int tp=x1>=x2?x1-x2:x1+10-x2; 43 mx=max(mx,tp),mi=min(mi,tp); 44 } 45 if(mx-mi>1) puts("-1"); 46 else if(mx==mi) printf("%d ",s[0]-'0'); 47 else { 48 q[1]=s[0]-'0'; 49 For(i,2,n) { 50 q[i]=q[i-1]+mi+(s[i-1]-'0'==(s[i-2]-'0'+mi+1)%10); 51 p[i]=1-i; 52 } 53 r=1e9,l=0; 54 For(i,1,n) For(j,1,n) if(i!=j) { 55 if(p[i]-p[j]>0) { 56 r=min(r,(db)(q[j]+1-q[i])/(db)(p[i]-p[j])); 57 } 58 else { 59 l=max(l,(db)(q[j]+1-q[i])/(db)(p[i]-p[j])); 60 } 61 } 62 r-=eps; l+=eps; 63 int k=0,d,bs=1; 64 for(;;k++) { 65 if((int)l!=(int)r||(l<=0&&r>=0)) { 66 d=(int)r; break; 67 } 68 bs*=10; 69 l*=10; 70 r*=10; 71 } 72 int ans=q[1]*bs+p[1]*d; 73 For(i,1,n) 74 ans=max(ans,q[i]*bs+p[i]*d); 75 printf("%d ",ans); 76 } 77 return 0; 78 }
蓝宝石的存在证明
【问题描述】
少年少女来到一座废弃的仓库寻找宝藏.一条早已被人遗忘的蓝宝石项链重
见天日,不幸发生了.
周围的人逐渐忘记少女是谁,只有少年仍旧记得,爱着少女.
决不会忘记,少年历下海誓山盟.终于,少年也忘记了,自己深爱着的少女.
少女并没有放弃,继续奋斗着.终于在那个仓库里,少女找到了破解这个禁锢的
希望.
那是一块石板,石板上曾有N 颗蓝宝石,M 条纹路连接着M 对宝石.完整的石板
具有强大的魔力,能够帮助许愿人冲破一切的束缚.
由于时间的侵蚀,石板上的蓝宝石早已不见踪影,现在的石板只是一些空的底
座和纹路.
同样,这些纹路也拥有特殊的能力,当一条纹路连接的两侧都没有蓝宝石时,许
愿者可以让这两个底座都出现一个蓝宝石;同样的,如果两侧都有宝石,那么许愿者
可以让它们都消失.
许愿者不能拿走宝石,否则会触怒石板.当每个位置上都有蓝宝石时,奇迹就会
发生.
少女最终完成了任务,世界重新记起了这个可怜的少女,可喜可贺可喜可贺.
世间流传少女的故事,石板谜题也同样作为经典问题留存至今.你对这个问题
非常感兴趣,并希望能够用最少的步数解决这个谜题.
(注:做题前请仔细阅读数据规模,以免不必要的麻烦.
【输入格式】
从文件 sapphire.in 中读入数据。
第一行两个正整数N, M ,其中N 为图的点数,M 为图的边数.
接下来M 行,每行两个正整数x, y,描述一条边.
【输出格式】
输出到文件 sapphire.out 中。一行描述最少的步数.如果无解输出−1.
【样例输入1】
6 5
1 2
1 3
1 4
2 5
2 6
【样例输出1】
5
【数据规模】
本题采用打包评测.
Subtask1(10points):N ≤ 10.
Subtask2(40points):N ≤ 100000且M = N − 1.
Subtask3(50points):N ≤ 100000且N − 1 ≤ M ≤ N .
所有数据均保证任意两个底座相互连通,且M ≤ N .
考试的时候写的辣鸡dp什么细节都没有,没考虑不用额外边的情况,只考虑了奇环,并且还没有加上额外的代价,成功GG
题解有个比较神的模型转换,二分图染色,原题转换为每个黑点上有一个棋子,要用最少都步数使棋子都移动到白点上.即把黑点没有棋子,白点有棋子看做有宝石,黑点有棋子,白点没有棋子看做无宝石,讨论环的奇偶
其实意思都差不多,我就直接用宝石都模型dp了.下面把有宝石的叫做非空点,没有的叫空点
用f[x]表示x点还需要与多少个空点相连,也就是需要它的父亲成为空点然后与他进行操作多少次.若f[x]为负,则表示需要与多少个非空点相连,同理.
每个点的初始f[x]为1,转移为每次减去它儿子的f值
这样若根的f值为0即存在合法操作.操作数就是abs(f[x])之和.
对于基环树,考虑多出的一条边带来的影响,显然是可以让这条边都两个点的f值同时加上一个数.
我把这条边的一个点作为了根,其实应该是无所谓的。这样我们设这个数为x,每个点的f变为两维,f[i]=a[i]*x+b[i];
如果环长为奇数,那么根的值f[rt]=2*x+b[rt],要使f[rt]=0,x有唯一解。
如果环长为偶数,那么f[rt]=b[rt],若b为0,x有解,否则无解。
有解时答案为abs(a[i]*x+b[i])之和,a[i]==0.1,-1,a=0时直接计算答案。
把x看做数轴上一点,a=-1时答案为b[i]到x的距离,a=1时答案为-b[i]到x的距离,那么把这些b拿出来取中位数即可。
注意的点就是
1.要考虑环的奇偶
2.非树边可能没用,应该设f[u]=x+1而不是f[u]=x
3.最后的代价要加上非树边的代价x。
4.数据有毒,存在自环,模型解释不通,强行理解为在自环上操作一次需要其他的地方两次操作才能变回来。那么特判一波,不需要这条边的情况算一次,再设这个点为2*x+1算一次。
1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include<map> 12 #define For(i,a,b) for(int i=(a);i<=(b);i++) 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 14 const int N=100007; 15 typedef long long LL; 16 typedef double db; 17 using namespace std; 18 int n,m; 19 20 template<typename T> void read(T &x) { 21 char ch=getchar(); x=0; T f=1; 22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 23 if(ch=='-') f=-1,ch=getchar(); 24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 25 } 26 27 int ecnt,fir[N],nxt[N<<1],to[N<<1]; 28 void add(int u,int v) { 29 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; 30 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; 31 } 32 33 int tot; 34 int dfs(int x,int fa) { 35 int rs=1; 36 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) { 37 rs-=dfs(to[i],x); 38 } 39 tot+=abs(rs); 40 return rs; 41 } 42 43 struct pt { 44 int a,b; // a*x+b; 45 pt(){} 46 pt(int a,int b):a(a),b(b){} 47 }val[N]; 48 pt operator -(const pt &A,const pt &B) { return pt(A.a-B.a,A.b-B.b); } 49 50 int fa[N],rt,spf; 51 int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } 52 53 int v[N]; 54 void dfs2(int x,int fa) { 55 if(x!=spf&&x!=rt) val[x]=pt(0,1); 56 else { if(rt==spf) val[x]=pt(2,1); else val[x]=pt(1,1); } 57 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) { 58 dfs2(to[i],x); 59 val[x]=val[x]-val[to[i]]; 60 } 61 if(val[x].a>0) v[++tot]=-val[x].b; 62 else if(val[x].a<0) v[++tot]=val[x].b; 63 } 64 65 #define DEBUG 66 int main() { 67 #ifdef DEBUG 68 freopen("sapphire.in","r",stdin); 69 freopen("sapphire.out","w",stdout); 70 #endif 71 read(n); read(m); 72 if(m==n-1) { 73 For(i,1,m) { 74 int u,v; 75 read(u); read(v); 76 add(u,v); 77 } 78 int rs=dfs(1,0); 79 if(rs==0) printf("%d ",tot); 80 else puts("-1"); 81 } 82 else { 83 For(i,1,n) fa[i]=i; 84 For(i,1,m) { 85 int u,v; 86 read(u); read(v); 87 if(find(u)!=find(v)) { 88 add(u,v); 89 fa[find(u)]=find(v); 90 } 91 else rt=u,spf=v; 92 } 93 dfs2(rt,0); 94 if(val[rt].a==0&&val[rt].b!=0) puts("-1"); 95 else { 96 if(val[rt].a==0) { 97 sort(v+1,v+tot+1); 98 int x=v[tot/2+1]; 99 int ans=abs(x); 100 For(i,1,n) 101 ans+=abs(val[i].a*x+val[i].b); 102 printf("%d ",ans); 103 } 104 else { 105 if(spf==rt&&val[rt].b==-1) { 106 tot=0; dfs(rt,0); 107 printf("%d ",tot); return 0; 108 } 109 else if(abs(val[rt].b)%val[rt].a!=0) puts("-1"); 110 else { 111 int x=-val[rt].b/val[rt].a; 112 tot=0; 113 For(i,1,n) 114 tot+=abs(val[i].a*x+val[i].b); 115 tot+=abs(x); 116 printf("%d ",tot); 117 } 118 } 119 } 120 } 121 return 0; 122 }
萤石的怠惰现象
【问题描述】
(由于一些不可描述的原因,故事被吃掉啦.)
给 出 一 张 点 数 为N ,边 数 为M 的 无 向 图G = (V, E).求 有 多 少V ′ ⊆ V ,满
足|V ′ | = k且对∀(u, v) ∈ E,满足u, v至少有一个不在V ′ 中,答案对M o取模.
【输入格式】
第一行四个整数N, M, k, M o.
接下来M 行,每行两个整数u, v,描述一条边.
【输出格式】
一行输出答案对M o取模的值.
【评分方式】
本题为提交答案题.你可以从下发的文件中得到subset1.in到subset10.in这10个
读入文件,并将答案输出到subset1.out到subset10.out这10个输出文件中.
对于1到10号测试点,如果你通过了这个测试点,你将分别可以得到
5, 6, 14, 8, 12, 11, 9, 13, 7, 15分.
【如果测试你的输出】
在终端中先切换到该试题的目录下(windows用户请使用cmd)
cdsubset
我们提供checker这个工具来测试你的输出文件是否正确。 使用这个工具的
方法是,在终端中运行
./checker < case no >
其中case no 是测试数据的编号。例如
./checker 3
将测试subset3.out是否正确。 (windows用户请使用checker 3)在你调用这个程序后,checker将根据你给出的输出文件给出测试的结果。
1.2点可以爆搜
3.4点树dp,需要滚动数组,4要放着跑一会。
5点是一个不完全的12*12的格子图,可以状压dp
剩下的点没做了。
老是喜欢把博客堆到一块写,一写就很久,有点累啊。。。