【自家测试】2018-5-9

翡翠的排挤原理
【前言】
一些以宝石命名的书籍,拥有神奇的能力,乃魔法之书.
魔法之书会自动挑选附近有意志讲述故事的人作为原著的表演者,在现实中
演绎故事,只有当故事迎来结尾,魔法之书才会合上.
时至今日,故事仍在不停地打开......
【问题描述】
少年注意到了一个少女.
少女总是孤身一人,受人冷落.不知从何时开始,不幸的魔法使,人们这样称呼
她.
少女总是在少年面前遭遇不幸:走路差点被车撞;被不知名的罪犯在桌子上乱
刻;下楼梯被看不见的凶手推下楼......
少年开始帮少女调查凶手,却找不到任何线索.在寻找的途中,少年和少女相恋
了,少女不再孤身一人.
调查仍在继续.少年又发现了一样少女被破坏的东西,那是一张纸,纸上似乎曾
写着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\n",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\n",ans);
76     } 
77     return 0;
78 }
View Code

 

蓝宝石的存在证明
【问题描述】
少年少女来到一座废弃的仓库寻找宝藏.一条早已被人遗忘的蓝宝石项链重
见天日,不幸发生了.
周围的人逐渐忘记少女是谁,只有少年仍旧记得,爱着少女.
决不会忘记,少年历下海誓山盟.终于,少年也忘记了,自己深爱着的少女.
少女并没有放弃,继续奋斗着.终于在那个仓库里,少女找到了破解这个禁锢的
希望.
那是一块石板,石板上曾有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\n",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\n",ans);
103             }
104             else {
105                 if(spf==rt&&val[rt].b==-1) {
106                     tot=0; dfs(rt,0);
107                     printf("%d\n",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\n",tot);
117                 }
118             }
119         }
120     }
121     return 0;
122 }
View Code

 

萤石的怠惰现象
【问题描述】
(由于一些不可描述的原因,故事被吃掉啦.)
给 出 一 张 点 数 为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

剩下的点没做了。

 

 老是喜欢把博客堆到一块写,一写就很久,有点累啊。。。

posted @ 2018-05-17 22:24  啊宸  阅读(326)  评论(0编辑  收藏  举报