POI 2012
题意去八中看,很清晰。
Festival:
嘛,首先可以很轻松的建出差分约束的模型,然后强连通缩点之后发现不同块的点是没有联系的,于是可以每块分开做。每块的答案就是点与点之间距离的最大值,提前floyd处理即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=610;
9 const int maxm=200010;
10 const int INF=0x3f3f3f3f;
11
12 int n,m1,m2,t,en,size,cnt,z[maxn],dfn[maxn],low[maxn],s[maxn],belong[maxn],dist[maxn][maxn];
13
14 bool instack[maxn];
15
16 struct edge
17 {
18 int e,d;
19 edge *next;
20 }*v[maxn],ed[maxm<<1];
21
22 void add_edge(int s,int e,int d)
23 {
24 en++;
25 ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
26 }
27
28 bool cmp(int a,int b)
29 {
30 return belong[a]<belong[b];
31 }
32
33 void dfs(int now)
34 {
35 t++;
36 dfn[now]=low[now]=t;
37 instack[now]=true;
38 s[++size]=now;
39 for (edge *e=v[now];e;e=e->next)
40 if (!dfn[e->e])
41 {
42 dfs(e->e);
43 low[now]=min(low[now],low[e->e]);
44 }
45 else
46 {
47 if (instack[e->e]) low[now]=min(low[now],dfn[e->e]);
48 }
49 if (dfn[now]==low[now])
50 {
51 cnt++;
52 while (s[size]!=now)
53 {
54 belong[s[size]]=cnt;
55 instack[s[size]]=false;
56 size--;
57 }
58 belong[now]=cnt;
59 instack[now]=false;
60 size--;
61 }
62 }
63
64 int main()
65 {
66 freopen("festival.in","r",stdin);
67 freopen("festival.out","w",stdout);
68
69 scanf("%d%d%d",&n,&m1,&m2);
70 for (int a=1;a<=m1;a++)
71 {
72 int s,e;
73 scanf("%d%d",&s,&e);
74 add_edge(s,e,1);
75 add_edge(e,s,-1);
76 }
77 for (int a=1;a<=m2;a++)
78 {
79 int s,e;
80 scanf("%d%d",&s,&e);
81 add_edge(s,e,0);
82 }
83 for (int a=1;a<=n;a++)
84 if (!dfn[a]) dfs(a);
85 for (int a=1;a<=n;a++)
86 for (int b=1;b<=n;b++)
87 dist[a][b]=-INF;
88 for (int a=1;a<=n;a++)
89 dist[a][a]=0;
90 for (int a=1;a<=n;a++)
91 for (edge *e=v[a];e;e=e->next)
92 if (belong[a]==belong[e->e]) dist[a][e->e]=max(dist[a][e->e],e->d);
93 for (int a=1;a<=n;a++)
94 for (int b=1;b<=n;b++)
95 if (dist[b][a]!=-INF)
96 for (int c=1;c<=n;c++)
97 if (dist[a][c]!=-INF) dist[b][c]=max(dist[b][c],dist[b][a]+dist[a][c]);
98 for (int a=1;a<=n;a++)
99 if (dist[a][a]>0)
100 {
101 printf("NIE\n");
102 return 0;
103 }
104 for (int a=1;a<=n;a++)
105 z[a]=a;
106 sort(z+1,z+n+1,cmp);
107 int ans=0;
108 for (int a=1;a<=n;)
109 {
110 int b=a;
111 while (b<=n && belong[z[b]]==belong[z[a]])
112 b++;
113 int delta=0;
114 for (int c=a;c<b;c++)
115 for (int d=a;d<b;d++)
116 delta=max(delta,abs(dist[z[c]][z[d]]));
117 ans+=delta+1;
118 a=b;
119 }
120 printf("%d\n",ans);
121
122 return 0;
123 }
Letters:
每次找最近的一个字母移动过去就完了,树状数组维护。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5 #include<queue>
6
7 using namespace std;
8
9 #ifdef unix
10 #define LL "%lld"
11 #else
12 #define LL "%I64d"
13 #endif
14
15 #define lb(x) ((x)&(-(x)))
16
17 const int maxn=1000010;
18
19 int n,z[maxn],y[maxn],match[maxn];
20
21 char s1[maxn],s2[maxn];
22
23 queue<int> que1[26],que2[26];
24
25 bool cmp(int a,int b)
26 {
27 return match[a]>match[b];
28 }
29
30 void modify(int p)
31 {
32 for (;p<=n;p+=lb(p))
33 y[p]++;
34 }
35
36 int query(int p)
37 {
38 int ans=0;
39 for (;p;p-=lb(p))
40 ans+=y[p];
41 return ans;
42 }
43
44 int main()
45 {
46 freopen("letters.in","r",stdin);
47 freopen("letters.out","w",stdout);
48
49 scanf("%d",&n);
50 scanf("%s",s1+1);
51 scanf("%s",s2+1);
52 for (int a=1;a<=n;a++)
53 {
54 int c1=s1[a]-'A';
55 int c2=s2[a]-'A';
56 if (c1==c2 && !que1[c2].size() && !que2[c1].size()) match[a]=a;
57 else
58 {
59 if (que2[c1].size())
60 {
61 match[a]=que2[c1].front();
62 que2[c1].pop();
63 }
64 else que1[c1].push(a);
65 if (que1[c2].size())
66 {
67 match[que1[c2].front()]=a;
68 que1[c2].pop();
69 }
70 else que2[c2].push(a);
71 }
72 }
73 for (int a=1;a<=n;a++)
74 z[a]=a;
75 sort(z+1,z+n+1,cmp);
76 long long ans=0;
77 for (int a=1;a<=n;a++)
78 {
79 int v=query(z[a]);
80 int x=z[a]-v;
81 ans+=abs(match[z[a]]-x);
82 modify(z[a]);
83 }
84 printf(LL "\n",ans);
85
86 return 0;
87 }
Distance:
这题挺不错,枚举中间负责过渡的是也就是两数的最大公约数,然后向上将答案做出来。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=100010;
9 const int maxv=1000010;
10 const int INF=0x3f3f3f3f;
11
12 int n,z[maxn],cnt[maxv],pla[maxv],ans[maxv],res[maxv],rex[maxv],num[maxv];
13
14 bool vis[maxv];
15
16 int main()
17 {
18 freopen("distance.in","r",stdin);
19 freopen("distance.out","w",stdout);
20
21 scanf("%d",&n);
22 int maxv=0;
23 for (int a=1;a<=n;a++)
24 {
25 scanf("%d",&z[a]);
26 cnt[z[a]]++;
27 if (cnt[z[a]]==1) res[z[a]]=a;
28 if (cnt[z[a]]==2) rex[z[a]]=a;
29 maxv=max(maxv,z[a]);
30 }
31 for (int a=2;a<=maxv;a++)
32 if (!vis[a])
33 {
34 for (int b=a;b<=maxv;b+=a)
35 {
36 int c=b;
37 while (c%a==0)
38 num[b]++,c/=a;
39 vis[b]=true;
40 }
41 }
42 memset(ans,0x3f,sizeof(ans));
43 for (int a=1;a<=maxv;a++)
44 {
45 int minv1=INF,minv2=INF;
46 int pla1=0,pla2=0;
47 for (int b=a;b<=maxv;b+=a)
48 if (cnt[b])
49 {
50 if (num[b]-num[a]<minv1 || (num[b]-num[a]==minv1 && res[b]<res[pla1]))
51 {
52 minv2=minv1;pla2=pla1;
53 minv1=num[b]-num[a];pla1=b;
54 }
55 else
56 {
57 if (num[b]-num[a]<minv2 || (num[b]-num[a]==minv2 && res[b]<res[pla2]))
58 {
59 minv2=num[b]-num[a];
60 pla2=b;
61 }
62 }
63 }
64 if (pla2)
65 {
66 for (int b=a;b<=maxv;b+=a)
67 {
68 int nowv=num[b]-num[a],nowp;
69 if (b==pla1) nowv+=minv2,nowp=pla2;
70 else nowv+=minv1,nowp=pla1;
71 if (nowv<ans[b] || (nowv==ans[b] && res[nowp]<res[pla[b]]))
72 {
73 ans[b]=nowv;
74 pla[b]=nowp;
75 }
76 }
77 }
78 }
79 for (int a=1;a<=n;a++)
80 if (cnt[z[a]]>1)
81 {
82 if (a==res[z[a]]) printf("%d\n",rex[z[a]]);
83 else printf("%d\n",res[z[a]]);
84 }
85 else printf("%d\n",res[pla[z[a]]]);
86
87 return 0;
88 }
Rendezvous:
一个一个地有向环套有向树,与处理完倍增神马的之后的就是简单的分情况讨论了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=500010;
9
10 int n,m,en,cnt,cir_len[maxn],f[maxn][20],q[maxn],depth[maxn],rt[maxn],belong[maxn],next[maxn],rank[maxn];
11
12 bool cir[maxn];
13
14 struct edge
15 {
16 int e;
17 edge *next;
18 }*v[maxn],ed[maxn];
19
20 void add_edge(int s,int e)
21 {
22 en++;
23 ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;
24 }
25
26 void solve_lca(int root)
27 {
28 int front=1,tail=1;
29 q[1]=root;
30 depth[root]=1;
31 rt[root]=root;
32 for (;front<=tail;)
33 {
34 int now=q[front++];
35 for (edge *e=v[now];e;e=e->next)
36 if (!cir[e->e])
37 {
38 depth[e->e]=depth[now]+1;
39 rt[e->e]=root;
40 belong[e->e]=cnt;
41 f[e->e][0]=now;
42 int p=now,x=0;
43 while (f[p][x])
44 {
45 f[e->e][x+1]=f[p][x];
46 p=f[p][x];
47 x++;
48 }
49 q[++tail]=e->e;
50 }
51 }
52 }
53
54 int get_lca(int p1,int p2)
55 {
56 if (depth[p1]<depth[p2]) swap(p1,p2);
57 int delta=depth[p1]-depth[p2],x=0;
58 while (delta)
59 {
60 if (delta&1) p1=f[p1][x];
61 delta>>=1;
62 x++;
63 }
64 x=0;
65 while (p1!=p2)
66 {
67 if (!x || f[p1][x]!=f[p2][x])
68 {
69 p1=f[p1][x];
70 p2=f[p2][x];
71 x++;
72 }
73 else x--;
74 }
75 return p1;
76 }
77
78 int main()
79 {
80 freopen("rendezvous.in","r",stdin);
81 freopen("rendezvous.out","w",stdout);
82
83 scanf("%d%d",&n,&m);
84 for (int a=1;a<=n;a++)
85 scanf("%d",&next[a]),add_edge(next[a],a);
86 for (int a=1;a<=n;a++)
87 if (!belong[a])
88 {
89 cnt++;
90 belong[a]=cnt;
91 int p=a;
92 while (true)
93 {
94 p=next[p];
95 if (belong[p]) break;
96 belong[p]=cnt;
97 }
98 int px=p;
99 int num=0;
100 while (true)
101 {
102 rank[px]=++num;
103 cir[px]=true;
104 px=next[px];
105 if (px==p) break;
106 }
107 cir_len[cnt]=num;
108 px=p;
109 while (true)
110 {
111 solve_lca(px);
112 px=next[px];
113 if (px==p) break;
114 }
115 }
116 for (int a=1;a<=m;a++)
117 {
118 int p1,p2;
119 scanf("%d%d",&p1,&p2);
120 if (belong[p1]!=belong[p2]) printf("-1 -1\n");
121 else
122 {
123 if (rt[p1]==rt[p2])
124 {
125 int lca=get_lca(p1,p2);
126 printf("%d %d\n",depth[p1]-depth[lca],depth[p2]-depth[lca]);
127 }
128 else
129 {
130 int x1=depth[p1]-1,x2=depth[p2]-1;
131 p1=rt[p1];
132 p2=rt[p2];
133 int v1,v2,v3,v4;
134 v1=x1+(rank[p2]>rank[p1] ? rank[p2]-rank[p1] : rank[p2]+cir_len[belong[p1]]-rank[p1]);
135 v2=x2;
136 v3=x1;
137 v4=x2+(rank[p1]>rank[p2] ? rank[p1]-rank[p2] : rank[p1]+cir_len[belong[p2]]-rank[p2]);
138 if (max(v1,v2)==max(v3,v4))
139 {
140 if (min(v1,v2)==min(v3,v4))
141 {
142 if (v1<v2) swap(v1,v3),swap(v2,v4);
143 }
144 else
145 {
146 if (min(v1,v2)>min(v3,v4)) swap(v1,v3),swap(v2,v4);
147 }
148 }
149 else
150 {
151 if (max(v1,v2)>max(v3,v4)) swap(v1,v3),swap(v2,v4);
152 }
153 printf("%d %d\n",v1,v2);
154 }
155 }
156 }
157
158 return 0;
159 }
Well:
二分答案。每次O(n)处理出每个位置所需要的代价。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<cctype>
5 #include<algorithm>
6
7 using namespace std;
8
9 const int BUF_SIZE = 30;
10 char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
11
12 #define PTR_NEXT() \
13 { \
14 buf_s ++; \
15 if (buf_s == buf_t) \
16 { \
17 buf_s = buf; \
18 buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
19 } \
20 }
21
22 #define readint(_n_) \
23 { \
24 while (*buf_s != '-' && !isdigit(*buf_s)) \
25 PTR_NEXT(); \
26 bool register _nega_ = false; \
27 if (*buf_s == '-') \
28 { \
29 _nega_ = true; \
30 PTR_NEXT(); \
31 } \
32 int register _x_ = 0; \
33 while (isdigit(*buf_s)) \
34 { \
35 _x_ = _x_ * 10 + *buf_s - '0'; \
36 PTR_NEXT(); \
37 } \
38 if (_nega_) \
39 _x_ = -_x_; \
40 (_n_) = (_x_); \
41 }
42
43 const int maxn=1000010;
44
45 int n,cnt[maxn],z[maxn],y[maxn];
46
47 long long m,value[maxn],num[maxn];
48
49 int check(int delta)
50 {
51 for (int a=1;a<=n;a++)
52 y[a]=z[a];
53 long long use=0;
54 for (int a=1;a<n;a++)
55 if (y[a+1]-y[a]>delta)
56 {
57 use+=y[a+1]-y[a]-delta;
58 y[a+1]=y[a]+delta;
59 }
60 for (int a=n;a>1;a--)
61 if (y[a-1]-y[a]>delta)
62 {
63 use+=y[a-1]-y[a]-delta;
64 y[a-1]=y[a]+delta;
65 }
66 if (use>m) return 0;
67 memset(num,0,sizeof(num));
68 memset(cnt,0,sizeof(cnt));
69 for (int a=1;a<=n;a++)
70 {
71 int to=min(a+y[a]/delta,n);
72 num[to]+=y[a]-(to-a)*delta;
73 cnt[to]++;
74 if (a!=1) num[a-1]-=y[a];
75 cnt[a]--;
76 }
77 long long sum=0;
78 int tot=0;
79 for (int a=n;a>=1;a--)
80 {
81 sum+=num[a]+(long long)tot*delta;
82 value[a]=sum;
83 tot+=cnt[a];
84 }
85 memset(num,0,sizeof(num));
86 memset(cnt,0,sizeof(cnt));
87 for (int a=n;a>=1;a--)
88 {
89 int to=max(a-y[a]/delta,1);
90 num[to]+=y[a]-(a-to)*delta;
91 cnt[to]++;
92 num[a]-=y[a];
93 if (a!=1) cnt[a-1]--;
94 }
95 sum=0;
96 tot=0;
97 for (int a=1;a<=n;a++)
98 {
99 sum+=num[a]+(long long)tot*delta;
100 value[a]+=sum;
101 tot+=cnt[a];
102 }
103 for (int a=1;a<=n;a++)
104 if (use+value[a]<=m) return a;
105 return 0;
106 }
107
108 int main()
109 {
110 freopen("well.in","r",stdin);
111 freopen("well.out","w",stdout);
112
113 scanf("%d%lld",&n,&m);
114 long long tot=0;
115 int maxv=0;
116 for (int a=1;a<=n;a++)
117 {
118 readint(z[a]);
119 tot+=z[a];
120 maxv=max(maxv,z[a]);
121 }
122 if (tot<=m)
123 {
124 printf("1 0\n");
125 return 0;
126 }
127 int l=0,r=maxv;
128 while (l+1!=r)
129 {
130 int m=(l+r)>>1;
131 if (check(m)==0) l=m;
132 else r=m;
133 }
134 printf("%d %d\n",check(r),r);
135
136 return 0;
137 }
Tour de Byteotia:
并查集把环都判掉就行。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=1000010;
9 const int maxm=2000010;
10
11 int n,m,k,ex[maxm][2],ans,cnt,f[maxn],res[maxm][2];
12
13 int getf(int now)
14 {
15 if (f[now]==now) return now;
16 else return f[now]=getf(f[now]);
17 }
18
19 int main()
20 {
21 freopen("tour.in","r",stdin);
22 freopen("tour.out","w",stdout);
23
24 scanf("%d%d%d",&n,&m,&k);
25 for (int a=1;a<=n;a++)
26 f[a]=a;
27 for (int a=1;a<=m;a++)
28 {
29 int s,e;
30 scanf("%d%d",&s,&e);
31 if (s>e) swap(s,e);
32 int f1=getf(s),f2=getf(e);
33 if (s<=k && e<=k)
34 {
35 if (f1==f2)
36 {
37 ans++;
38 res[ans][0]=s;res[ans][1]=e;
39 }
40 else f[f1]=f2;
41 }
42 else
43 {
44 if (s>k) f[f1]=f2;
45 else
46 {
47 cnt++;
48 ex[cnt][0]=s;ex[cnt][1]=e;
49 }
50 }
51 }
52 for (int a=1;a<=cnt;a++)
53 {
54 int f1=getf(ex[a][0]),f2=getf(ex[a][1]);
55 if (f1==f2)
56 {
57 ans++;
58 res[ans][0]=ex[a][0];
59 res[ans][1]=ex[a][1];
60 }
61 else f[f1]=f2;
62 }
63 printf("%d\n",ans);
64 for (int a=1;a<=ans;a++)
65 printf("%d %d\n",res[a][0],res[a][1]);
66
67 return 0;
68 }
Vouchers:
维护一下选某个值应该从哪个地方开始然后暴力就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=1000010;
9
10 int n,m,start[maxn];
11
12 bool lucky[maxn],use[maxn];
13
14 long long ans[maxn];
15
16 int main()
17 {
18 freopen("vouchers.in","r",stdin);
19 freopen("vouchers.out","w",stdout);
20
21 scanf("%d",&m);
22 int maxv=0;
23 for (int a=1;a<=m;a++)
24 {
25 int v;
26 scanf("%d",&v);
27 lucky[v]=true;
28 maxv=max(v,maxv);
29 }
30 scanf("%d",&n);
31 long long tot=0;
32 int cnt=0;
33 for (int a=1;a<=maxv;a++)
34 start[a]=a;
35 for (int a=1;a<=n;a++)
36 {
37 int v;
38 scanf("%d",&v);
39 int p=start[v];
40 for (int b=1;b<=v;b++)
41 {
42 while (p<=maxv && use[p])
43 p+=v;
44 if (p>maxv) break;
45 use[p]=true;
46 if (lucky[p]) ans[++cnt]=tot+b;
47 }
48 start[v]=p;
49 tot+=v;
50 }
51 printf("%d\n",cnt);
52 for (int a=1;a<=cnt;a++)
53 printf("%lld\n",ans[a]);
54
55 return 0;
56 }
A Horrible Poem:
hash,对于每个长度只用枚举因子长度hash判断即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5 #include<vector>
6
7 using namespace std;
8
9 #define ull unsigned long long
10
11 const int maxn=500010;
12 const ull base=10007;
13
14 int n,m;
15
16 ull bit[maxn],h[maxn];
17
18 char s[maxn];
19
20 bool check[maxn];
21
22 vector < pair < int , int > > prime[maxn];
23
24 int calc(int l,int r)
25 {
26 return h[r]-h[l-1]*bit[r-l+1];
27 }
28
29 int main()
30 {
31 freopen("poem.in","r",stdin);
32 freopen("poem.out","w",stdout);
33
34 scanf("%d",&n);
35 scanf("%s",s+1);
36 for (int a=1;a<=n;a++)
37 h[a]=h[a-1]*base+s[a];
38 bit[0]=1;
39 for (int a=1;a<=n;a++)
40 bit[a]=bit[a-1]*base;
41 for (int a=2;a<=n;a++)
42 if (!check[a])
43 {
44 for (int b=a;b<=n;b+=a)
45 {
46 int v=b;
47 int cnt=0;
48 while (v%a==0)
49 v/=a,cnt++;
50 prime[b].push_back(make_pair(a,cnt));
51 check[b]=true;
52 }
53 }
54 scanf("%d",&m);
55 for (int a=1;a<=m;a++)
56 {
57 int l,r;
58 scanf("%d%d",&l,&r);
59 int len=r-l+1;
60 int ans=len;
61 for (int b=0;b<(int)prime[len].size();b++)
62 {
63 int bx=prime[len][b].first;
64 int cnt=prime[len][b].second;
65 int mul=1;
66 for (int c=1;c<=cnt;c++)
67 mul*=bx;
68 for (;cnt--;)
69 {
70 int lx=len/mul;
71 if (calc(l,r-lx)==calc(l+lx,r))
72 {
73 ans/=mul;
74 break;
75 }
76 mul/=bx;
77 }
78 }
79 printf("%d\n",ans);
80 }
81
82 return 0;
83 }
Fibonacci Representation:
直接记忆化搜索,每次只可能选择最相邻的两个斐波那契数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5 #include<map>
6
7 using namespace std;
8
9 long long f[100];
10
11 map<long long,int> ma;
12
13 int dfs(long long v)
14 {
15 if (ma[v]) return ma[v];
16 for (int a=1;a<=90;a++)
17 if (f[a+1]>v)
18 {
19 if (f[a]==v) return ma[v]=1;
20 return ma[v]=min(dfs(v-f[a]),dfs(f[a+1]-v))+1;
21 }
22 return -1;
23 }
24
25 int main()
26 {
27 freopen("fibonacci.in","r",stdin);
28 freopen("fibonacci.out","w",stdout);
29
30 f[1]=1;
31 f[2]=2;
32 for (int a=3;a<=90;a++)
33 f[a]=f[a-1]+f[a-2];
34 int t;
35 scanf("%d",&t);
36 for (int a=1;a<=t;a++)
37 {
38 long long v;
39 scanf("%lld",&v);
40 printf("%d\n",dfs(v));
41 }
42
43 return 0;
44 }
Squarks:
最小的是a1+a2,其次是a1+a3,枚举a2+a3是谁,接下来的可以依次判断。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=310;
9
10 int n,m,res[maxn],ans[maxn][maxn],z[maxn*maxn],cnt;
11
12 bool use[maxn*maxn];
13
14 void check(int p)
15 {
16 memset(use,false,sizeof(use));
17 if ((z[1]+z[2]+z[p])&1) return;
18 res[1]=(z[1]+z[2]+z[p])/2-z[p];
19 res[2]=z[1]-res[1];
20 res[3]=z[2]-res[1];
21 use[1]=use[2]=use[p]=true;
22 for (int a=4,b=3;a<=n;a++)
23 {
24 while (b<=m && use[b])
25 b++;
26 if (b>m) return;
27 res[a]=z[b]-res[1];
28 use[b]=true;
29 for (int c=2;c<a;c++)
30 {
31 if (res[c]>res[a]) return;
32 int v=res[c]+res[a];
33 int p=lower_bound(z+1,z+m+1,v)-z;
34 if (z[p]!=v) return;
35 int px=p;
36 while (px && z[px]==z[p])
37 px--;
38 px++;
39 while (px<=m && z[px]==z[p] && use[px])
40 px++;
41 if (z[px]!=z[p] || use[px]) return;
42 p=px;
43 use[p]=true;
44 }
45 }
46 cnt++;
47 for (int a=1;a<=n;a++)
48 ans[cnt][a]=res[a];
49 }
50
51 int main()
52 {
53 freopen("squarks.in","r",stdin);
54 freopen("squarks.out","w",stdout);
55
56 scanf("%d",&n);
57 m=n*(n-1)/2;
58 for (int a=1;a<=m;a++)
59 scanf("%d",&z[a]);
60 sort(z+1,z+m+1);
61 for (int a=3;a<=m;)
62 {
63 check(a);
64 int b=a;
65 while (b<=m && z[b]==z[a])
66 b++;
67 a=b;
68 }
69 printf("%d\n",cnt);
70 for (int a=1;a<=cnt;a++)
71 for (int b=1;b<=n;b++)
72 {
73 printf("%d",ans[a][b]);
74 if (b==n) printf("\n");
75 else printf(" ");
76 }
77
78 return 0;
79 }
Bidding:
由于x只有可能是2^a*3^b,所以可能性并不多,直接暴力DP就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include "cliclib.h"
5
6 using namespace std;
7
8 const int maxn=30010;
9
10 int mul2[20],mul3[20];
11
12 bool win[maxn][16][12];
13
14 int main()
15 {
16 freopen("bidding.in","r",stdin);
17 freopen("bidding.out","w",stdout);
18
19 int n=inicjuj();
20 int v=1,cnt1=0,cnt2=0;
21 while (v<=n)
22 mul2[cnt1++]=v,v<<=1;
23 mul2[cnt1]=v;
24 v=1;
25 mul3[0]=1;
26 while (v<=n)
27 mul3[cnt2++]=v,v*=3;
28 mul3[cnt2]=v;
29 for (int a=n;a>=0;a--)
30 for (int b=cnt1;b>=0;b--)
31 for (int c=cnt2;c>=0;c--)
32 if (a+mul2[b]*mul3[c]<n)
33 {
34 if (b!=cnt1 && !win[a][b+1][c]) win[a][b][c]=true;
35 if (c!=cnt2 && !win[a][b][c+1]) win[a][b][c]=true;
36 if (!win[a+mul2[b]*mul3[c]][0][0]) win[a][b][c]=true;
37 }
38 int sum=0,pow2=0,pow3=0;
39 while(true)
40 {
41 if (pow2<cnt1 && !win[sum][pow2+1][pow3]) alojzy(2),pow2++;
42 else
43 {
44 if (pow3<cnt2 && !win[sum][pow2][pow3+1]) alojzy(3),pow3++;
45 else alojzy(1),sum+=mul2[pow2]*mul3[pow3],pow2=pow3=0;
46 }
47 int x=bajtazar();
48 if (x==1) sum+=mul2[pow2]*mul3[pow3],pow2=pow3=0;
49 if (x==2) pow2++;
50 if (x==3) pow3++;
51 }
52
53 return 0;
54 }
Salaries:
做出每个点的上限,排序之后依次检验。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<cctype>
5 #include<algorithm>
6
7 using namespace std;
8
9 const int BUF_SIZE = 30;
10 char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
11
12 #define PTR_NEXT() \
13 { \
14 buf_s ++; \
15 if (buf_s == buf_t) \
16 { \
17 buf_s = buf; \
18 buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
19 } \
20 }
21
22 #define readint(_n_) \
23 { \
24 while (*buf_s != '-' && !isdigit(*buf_s)) \
25 PTR_NEXT(); \
26 bool register _nega_ = false; \
27 if (*buf_s == '-') \
28 { \
29 _nega_ = true; \
30 PTR_NEXT(); \
31 } \
32 int register _x_ = 0; \
33 while (isdigit(*buf_s)) \
34 { \
35 _x_ = _x_ * 10 + *buf_s - '0'; \
36 PTR_NEXT(); \
37 } \
38 if (_nega_) \
39 _x_ = -_x_; \
40 (_n_) = (_x_); \
41 }
42
43 const int maxn=1000010;
44
45 int n,en,f[maxn],z[maxn],q[maxn],res[maxn],y[maxn],limit[maxn],show[maxn],x[maxn],last[maxn];
46
47 struct edge
48 {
49 int e;
50 edge *next;
51 }*v[maxn],ed[maxn];
52
53 void add_edge(int s,int e)
54 {
55 en++;
56 ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;
57 }
58
59 bool cmp(int a,int b)
60 {
61 return limit[a]<limit[b];
62 }
63
64 int main()
65 {
66 freopen("salaries.in","r",stdin);
67 freopen("salaries.out","w",stdout);
68
69 readint(n);
70 int root;
71 for (int a=1;a<=n;a++)
72 {
73 readint(f[a]);
74 readint(z[a]);
75 res[a]=z[a];
76 show[z[a]]++;
77 if (f[a]==a) root=a,f[a]=0;
78 else add_edge(f[a],a);
79 }
80 for (int a=1;a<=n;a++)
81 if (!show[a]) last[a]=a;
82 else last[a]=last[a-1];
83 int front=1,tail=1;
84 q[1]=root;
85 front=1,tail=1;
86 int cnt=0;
87 for (;front<=tail;)
88 {
89 int now=q[front++];
90 for (edge *e=v[now];e;e=e->next)
91 {
92 q[++tail]=e->e;
93 if (!z[e->e])
94 {
95 y[++cnt]=e->e;
96 limit[e->e]=max(limit[now]-1,z[now]-1);
97 limit[e->e]=last[limit[e->e]];
98 }
99 }
100 }
101 res[root]=n;
102 int maxv=0;
103 memset(z,0,sizeof(z));
104 for (int a=1;a<=cnt;a++)
105 {
106 z[limit[y[a]]]++;
107 maxv=max(maxv,limit[y[a]]);
108 }
109 for (int a=1;a<=maxv;a++)
110 z[a]+=z[a-1];
111 for (int a=cnt;a>=1;a--)
112 x[z[limit[y[a]]]--]=y[a];
113 for (int a=1;a<=cnt;a++)
114 y[a]=x[a];
115 int tot=0,use=0;
116 int hzc=0;
117 for (int a=1,b=1;a<=cnt;a++)
118 {
119 int now=y[a];
120 tot=limit[now];
121 while (b<=tot)
122 {
123 if (!show[b]) x[++hzc]=b;
124 else use++;
125 b++;
126 }
127 if (limit[now]!=limit[y[a-1]] && tot-use==1) res[now]=x[hzc];
128 use++;
129 }
130 for (int a=1;a<=n;a++)
131 printf("%d\n",res[a]);
132
133 return 0;
134 }
Leveling Ground:
差分之后转化为单点,做出单点最小后统一正负号。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5 #include<queue>
6
7 using namespace std;
8
9 #define calc(x,y,d) (abs(x-(long long)v2*d)+abs(y+(long long)v1*d))
10
11 const int maxn=100010;
12
13 int n,v1,v2,z[maxn];
14
15 long long x[maxn],y[maxn];
16
17 struct rec
18 {
19 int p;
20 long long v;
21 rec(){}
22 rec(int a,long long b)
23 {
24 p=a;v=b;
25 }
26 bool operator<(const rec &a)const
27 {
28 return v>a.v;
29 }
30 };
31
32 int gcd(int a,int b)
33 {
34 if (!b) return a;
35 else return gcd(b,a%b);
36 }
37
38 int phi(int v)
39 {
40 int x=v;
41 for (int a=2;a*a<=v;a++)
42 if (v%a==0)
43 {
44 x=x/a*(a-1);
45 while (v%a==0)
46 v/=a;
47 }
48 if (v!=1) x=x/v*(v-1);
49 return x;
50 }
51
52 int mul(int a,int b,int mo)
53 {
54 int ans=1;
55 while (b)
56 {
57 if (b&1) ans=(long long)ans*a%mo;
58 a=(long long)a*a%mo;
59 b>>=1;
60 }
61 return ans;
62 }
63
64 int main()
65 {
66 //freopen("ground.in","r",stdin);
67 //freopen("ground.out","w",stdout);
68
69 scanf("%d%d%d",&n,&v1,&v2);
70 int g=gcd(v1,v2);
71 for (int a=1;a<=n;a++)
72 {
73 scanf("%d",&z[a]);
74 if (z[a]%g!=0)
75 {
76 printf("-1\n");
77 return 0;
78 }
79 z[a]/=g;
80 }
81 v1/=g;v2/=g;
82 z[n+1]=-z[n];
83 for (int a=n;a>1;a--)
84 z[a]-=z[a-1];
85 n++;
86 if (v1==v2)
87 {
88 long long sum=0;
89 for (int a=1;a<=n;a++)
90 sum+=abs(z[a]);
91 printf("%lld\n",sum>>1);
92 return 0;
93 }
94 if (v1>v2) swap(v1,v2);
95 int x0=mul(v1,phi(v2)-1,v2);
96 int y0=(-(long long)x0*v1+1)/v2;
97 for (int a=1;a<=n;a++)
98 {
99 x[a]=(long long)x0*z[a];
100 y[a]=(long long)y0*z[a];
101 long long l=-z[a],r=z[a];
102 if (l>r) swap(l,r);
103 while (l+10<=r)
104 {
105 int dist=(r-l+1)/3;
106 long long z1=calc(x[a],y[a],(l+dist));
107 long long z2=calc(x[a],y[a],(r-dist));
108 if (z1<=z2) r=r-dist;
109 else l=l+dist;
110 }
111 long long minv=calc(x[a],y[a],r);
112 int p=r;
113 for (int b=l;b<r;b++)
114 {
115 long long value=calc(x[a],y[a],b);
116 if (value<minv) minv=value,p=b;
117 }
118 x[a]=x[a]-(long long)p*v2;
119 y[a]=y[a]+(long long)p*v1;
120 }
121 long long sum=0;
122 for (int a=1;a<=n;a++)
123 sum+=x[a];
124 if (sum<0)
125 {
126 for (int a=1;a<=n;a++)
127 swap(x[a],y[a]);
128 swap(v1,v2);
129 sum=0;
130 for (int a=1;a<=n;a++)
131 sum+=x[a];
132 }
133 sum/=v2;
134 priority_queue<rec> heap;
135 for (int a=1;a<=n;a++)
136 heap.push(rec(a,abs(x[a]-v2)+abs(y[a]+v1)-abs(x[a])-abs(y[a])));
137 for (int a=1;a<=sum;a++)
138 {
139 int p=heap.top().p;
140 heap.pop();
141 x[p]-=v2;
142 y[p]+=v1;
143 heap.push(rec(p,abs(x[p]-v2)+abs(y[p]+v1)-abs(x[p])-abs(y[p])));
144 }
145 long long ans=0;
146 for (int a=1;a<=n;a++)
147 ans+=abs(x[a])+abs(y[a]);
148 printf("%lld\n",ans>>1);
149
150 return 0;
151 }
Minimalist Security:
每个联通块设个未知数,然后检验所有边。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=500010;
9 const int maxm=6000010;
10
11 int n,m,en,z[maxn],q[maxn];
12
13 long long value[maxn][2];
14
15 bool vis[maxn];
16
17 struct edge
18 {
19 int e,d;
20 edge *next;
21 }*v[maxn],ed[maxm];
22
23 void add_edge(int s,int e,int d)
24 {
25 en++;
26 ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
27 }
28
29 int main()
30 {
31 freopen("security.in","r",stdin);
32 freopen("security.out","w",stdout);
33
34 scanf("%d%d",&n,&m);
35 for (int a=1;a<=n;a++)
36 scanf("%d",&z[a]);
37 for (int a=1;a<=m;a++)
38 {
39 int s,e,d;
40 scanf("%d%d%d",&s,&e,&d);
41 add_edge(s,e,z[s]+z[e]-d);
42 add_edge(e,s,z[s]+z[e]-d);
43 }
44 long long minv=0,maxv=0;
45 for (int a=1;a<=n;a++)
46 if (!vis[a])
47 {
48 long long L=0,R=z[a];
49 vis[a]=true;
50 int front=1,tail=1;
51 q[1]=a;
52 value[a][0]=1;value[a][1]=0;
53 long long sum1=1,sum2=0;
54 for (;front<=tail;)
55 {
56 int now=q[front++];
57 for (edge *e=v[now];e;e=e->next)
58 if (!vis[e->e])
59 {
60 value[e->e][0]=-value[now][0];
61 value[e->e][1]=e->d-value[now][1];
62 if (value[e->e][0]>0)
63 {
64 L=max(L,(-value[e->e][1]-1)/value[e->e][0]+1);
65 R=min(R,(z[e->e]-value[e->e][1])/value[e->e][0]);
66 }
67 else
68 {
69 L=max(L,(value[e->e][1]-z[e->e]-1)/(-value[e->e][0])+1);
70 R=min(R,value[e->e][1]/(-value[e->e][0]));
71 }
72 sum1+=value[e->e][0];sum2+=value[e->e][1];
73 q[++tail]=e->e;
74 vis[e->e]=true;
75 }
76 else
77 {
78 long long v1=value[now][0]+value[e->e][0];
79 long long v2=value[now][1]+value[e->e][1];
80 if (v1==0)
81 {
82 if (v2!=e->d)
83 {
84 printf("NIE\n");
85 return 0;
86 }
87 }
88 else
89 {
90 if ((v2-e->d)%v1!=0)
91 {
92 printf("NIE\n");
93 return 0;
94 }
95 long long x=(e->d-v2)/v1;
96 L=max(L,x);
97 R=min(R,x);
98 }
99 }
100 }
101 if (L>R)
102 {
103 printf("NIE\n");
104 return 0;
105 }
106 long long v1=L*sum1+sum2;
107 long long v2=R*sum1+sum2;
108 minv+=min(v1,v2);
109 maxv+=max(v1,v2);
110 }
111 printf("%lld %lld\n",minv,maxv);
112
113 return 0;
114 }
Warehouse Store:
这贪心已经考烂了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5 #include<queue>
6
7 using namespace std;
8
9 const int maxn=250010;
10
11 int n,res[maxn],v1[maxn],v2[maxn];
12
13 struct rec
14 {
15 int id,v;
16 rec(){}
17 rec(int a,int b)
18 {
19 id=a;v=b;
20 }
21 bool operator<(const rec &a)const
22 {
23 return v<a.v;
24 }
25 };
26
27 int main()
28 {
29 freopen("store.in","r",stdin);
30 freopen("store.out","w",stdout);
31
32 scanf("%d",&n);
33 for (int a=1;a<=n;a++)
34 scanf("%d",&v1[a]);
35 for (int a=1;a<=n;a++)
36 scanf("%d",&v2[a]);
37 priority_queue<rec> heap;
38 long long rest=0;
39 for (int a=1;a<=n;a++)
40 {
41 rest+=v1[a];
42 if (rest>=v2[a]) heap.push(rec(a,v2[a])),rest-=v2[a];
43 else
44 {
45 if (heap.size() && heap.top().v>v2[a])
46 {
47 rest+=heap.top().v;
48 rest-=v2[a];
49 heap.pop();
50 heap.push(rec(a,v2[a]));
51 }
52 }
53 }
54 int ans=0;
55 while (heap.size())
56 res[++ans]=heap.top().id,heap.pop();
57 sort(res+1,res+ans+1);
58 printf("%d\n",ans);
59 for (int a=1;a<=ans;a++)
60 {
61 printf("%d",res[a]);
62 if (a==ans) printf("\n");
63 else printf(" ");
64 }
65
66 return 0;
67 }
Prefixuffix:
利用单调性使后面的检验做到O(N),卡hash。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=1000010;
9 const int base1=10007;
10 const int mo1=1000000003;
11 const int base2=10003;
12 const int mo2=1000000007;
13
14 int n,h1[maxn],bit1[maxn],h2[maxn],bit2[maxn];
15
16 char s[maxn];
17
18 pair<int,int> calc(int l,int r)
19 {
20 return make_pair((h1[r]-(long long)h1[l-1]*bit1[r-l+1]%mo1+mo1)%mo1,(h2[r]-(long long)h2[l-1]*bit2[r-l+1]%mo2+mo2)%mo2);
21 }
22
23 int main()
24 {
25 freopen("prefixuffix.in","r",stdin);
26 freopen("prefixuffix.out","w",stdout);
27
28 scanf("%d",&n);
29 scanf("%s",s+1);
30 for (int a=1;a<=n;a++)
31 h1[a]=((long long)h1[a-1]*base1+s[a])%mo1;
32 bit1[0]=1;
33 for (int a=1;a<=n;a++)
34 bit1[a]=(long long)bit1[a-1]*base1%mo1;
35 for (int a=1;a<=n;a++)
36 h2[a]=((long long)h2[a-1]*base2+s[a])%mo2;
37 bit2[0]=1;
38 for (int a=1;a<=n;a++)
39 bit2[a]=(long long)bit2[a-1]*base2%mo2;
40 int ans=0;
41 for (int a=(n>>1),b=0;a>=0;a--)
42 {
43 b+=2;
44 while (b && (a+b>(n>>1) || calc(a+1,a+b)!=calc(n-a-b+1,n-a)))
45 b--;
46 if (calc(1,a)==calc(n-a+1,n)) ans=max(ans,a+b);
47 }
48 printf("%d\n",ans);
49
50 return 0;
51 }