去年十月拿了省一真是挺开心的。。。。
总算是订正得差不多了。。。(斗地主一题实在受不了!!!)
D1T1 神奇的幻方
裸模拟就不说了。。
#include
#include
using namespace std;
const int maxn = 50;
int a[maxn][maxn],i,j,n,r,c;
int main()
{
cin >> n;
int mr = n / 2 + 1;
int mc = mr;
a[1][mc] = 1;
r = 1; c = mc;
for (i = 2; i <= n*n; i++) {
if (r == 1 && c != n) {
a[n][c+1] = i;
r = n; c = c+1;
continue;
}
if (r != 1 && c == n) {
a[r-1][1] = i;
r = r-1; c = 1;
continue;
}
if (r == 1 && c == n) {
a[r+1][c] = i;
r = r+1;
continue;
}
if (!a[r-1][c+1]) {
a[r-1][c+1] = i;
r = r-1; c = c+1;
}
else {
a[r+1][c] = i;
r = r+1;
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j < n; j++) printf("%d ",a[i][j]);
printf("%d\n",a[i][j]);
}
return 0;
}
D1T2 信息传递
显然找到图中最大环即可
苟蒻用tarjan算法。。不过还好栈有8MB。。比赛的时候完全没考虑过爆栈
#include
#include
#include
#include
using namespace std;
const int maxn = 2e5 + 10;
int sccno[maxn],pre[maxn],low[maxn],Size[maxn],To[maxn],n,i,j,ans = 1E9,d_t = 0,cur = 0;
stack s;
void dfs(int k)
{
pre[k] = low[k] = ++d_t;
s.push(k);
if (!pre[To[k]]) {
dfs(To[k]);
low[k] = min(low[k],low[To[k]]);
}
else {
if (!sccno[To[k]]) low[k] = min(low[k],low[To[k]]);
}
if (pre[k] == low[k]) {
int S = 0; ++cur;
while (1) {
int now = s.top();
sccno[now] = cur;
++S; s.pop();
if (now == k) break;
}
Size[cur] = S;
}
}
int main()
{
cin >> n;
for (i = 1; i <= n; i++) scanf("%d",&To[i]);
memset(pre,0,sizeof(pre));
for (i = 1; i <= n; i++)
if (!pre[i]) dfs(i);
for (i = 1; i <= n; i++)
if (Size[sccno[i]] != 1) ans = min(ans,Size[sccno[i]]);
cout << ans;
return 0;
}
D1T3 斗地主
苟蒻终于在2016.3.12A了这道狗日的深搜
提炼一道正解的观点
除了三种龙以外,其他牌同牌点顺序无关,见qwork函数直接算出
剩下就是枚举龙了
#include
#include
#include
#include
using namespace std;
const int maxn = 15;
int n,t,ans,b[4],a[maxn];
int qwork()
{
int c1,c2,c3,c4,cnt;
c1 = c2 = c3 = c4 = cnt = 0;
for (int i = 0; i < 14; i++) {
if (a[i] == 1) ++c1;
if (a[i] == 2) ++c2;
if (a[i] == 3) ++c3;
if (a[i] == 4) ++c4;
}
while (c4 && c2 > 1) --c4,c2-=2,++cnt;
while (c4 && c1 > 1) --c4,c1-=2,++cnt;
while (c3 && c2) --c3,--c2,++cnt;
while (c3 && c1) --c3,--c1,++cnt;
while (c4 && c2) --c4,--c2,++cnt;
return cnt+c1+c2+c3+c4;
}
void dfs(int now,int rest)
{
if (now >= ans) return;
int ret = qwork(); ans = min(ans,now+ret);
for (int i = 0; i <= 7; i++) if (a[i]) {
int j = i;
while (a[j]) ++j;
if (j - i >= 5) {
--j;
j = min(j,11);
for (int l = j; l >= i+4; l--) {
for (int k = i; k <= l; k++) --a[k];
dfs(now+1,rest-l+i-1);
for (int k = i; k <= l; k++) ++a[k];
}
}
}
for (int i = 0; i <= 9; i++) if (a[i] >= 2) {
int j = i;
while (a[j] >= 2) ++j;
if (j - i >= 3) {
--j;
j = min(j,11);
for (int l = j; l >= i+2; l--) {
for (int k = i; k <= l; k++) a[k] -= 2;
dfs(now+1,rest-2*(l-i+1));
for (int k = i; k <= l; k++) a[k] += 2;
}
}
}
for (int i = 0; i <= 10; i++) if (a[i] >= 3) {
int j = i;
while (a[j] >= 3) ++j;
if (j - i >= 2) {
--j;
j = min(j,11);
for (int l = j; l >= i+1; l--) {
for (int k = i; k <= l; k++) a[k] -= 3;
dfs(now+1,rest-3*(l-i+1));
for (int k = i; k <= l; k++) a[k] += 3;
}
}
}
}
void READ()
{
memset(a,0,sizeof(a));
for (int i = 1; i <= n; i++) {
int x,y; scanf("%d%d",&x,&y);
if (x > 2) x -= 3;
else if (!x) x = 13;
else x += 10;
++a[x];
}
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
cin >> t >> n;
while (t--) {
READ();
ans = n;
dfs(0,n);
printf("%d\n",ans);
}
return 0;
}
D2T1 跳石头
简单的二分,比赛的时候竟然忘了特判最后一枚石头(即终点)
还好那只有一个点。。。
#include
#include
using namespace std;
const int maxn = 5e4 + 50;
int s[maxn],l,m,n,i,j;
bool Judge(int now)
{
int rig = 0;
int sum = 0;
for (i = 1; i <= n; i++) {
if (s[i] - rig < now) ++sum;
else rig = s[i];
}
if (l - rig < now) ++sum;
return sum <= m;
}
int main()
{
cin >> l >> n >> m;
for (i = 1; i <= n; i++) scanf("%d",&s[i]);
int L = 0,R = l+10;
while (R - L > 1) {
int mid = (R+L) >> 1;
if (Judge(mid)) L = mid;
else R = mid;
}
if (Judge(R)) cout << R;
else cout << L;
return 0;
}
D2T2 子串
dp。。。
然而苟蒻太水现场不会做只骗了40分
f[k][i][j]:第一个串到i位置第二个串到j位置,且用第一个串的i字符成为第二个串的j字符,已选用k段的方案数
那么方案转移就变为延续上一种方案的尾部或开一段新的子串
详见代码。。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const LL mo = 1000000007;
LL f[2][1010][210],sum[2][1010][210];
char s1[1010],s2[210];
int n,m,k,i,j;
int main()
{
cin >> n >> m >> k;
scanf("%s",1+s1);
scanf("%s",1+s2);
f[0][0][0] = 1;
for (i = 0; i <= n; i++) sum[0][i][0] = 1;
for (int l = 1; l <= k; l++) {
memset(f[l&1],0,sizeof(f[l&1]));
memset(sum[l&1],0,sizeof(sum[l&1]));
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++) {
if (s1[i] == s2[j]) {
f[l&1][i][j] = sum[(l-1)&1][i-1][j-1];
if (s1[i-1] == s2[j-1])
f[l&1][i][j] = (f[l&1][i][j]+f[l&1][i-1][j-1]) % mo;
}
sum[l&1][i][j] = (f[l&1][i][j] + sum[l&1][i-1][j]) % mo;
}
}
cout << sum[k&1][n][m];
return 0;
}
D2T3
比赛强行朴素算法35分。。
据说只有O(n)的神算法才能AC?
苟蒻学了O(nlogn)的使用树上前缀和的算法
显然每个运输方案对应树上1或2条链
用倍增算法求出每个方案初始耗时,经过的路径
二分答案,用树上前缀和求之
(bzoj上竟然可以过)
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 3E5 + 10;
typedef int LL;
struct E{
LL to,w,num;
};
struct Q{
LL x,y,sum,fa;
}q[maxn];
LL n,m,i,j,du[maxn],pass[maxn];
LL anc[maxn][20],sum[maxn][20],t[maxn],vis[maxn],L[maxn],Fa[maxn],Mark[maxn];
vector v[maxn];
vector Last;
queue qu;
queue qu2;
void Bfs(int x)
{
qu2.push(x);
while (!qu2.empty()) {
bool flag = 0;
LL k = qu2.front(); qu2.pop();
for (int l = 0; l < v[k].size(); l++) {
int to = v[k][l].to;
if (L[to]) continue;
flag = 1;
L[to] = L[k] + 1;
anc[to][0] = k;
sum[to][0] = v[k][l].w;
Fa[to] = v[k][l].num;
++du[k];
qu2.push(to);
}
if (!flag) Last.push_back(k);
}
}
void LCA_pre()
{
for (int l = 1; l < 20; l++)
for (i = 1; i <= n; i++) {
anc[i][l] = anc[anc[i][l-1]][l-1];
sum[i][l] = sum[anc[i][l-1]][l-1] + sum[i][l-1];
}
}
void solve()
{
LL x = q[i].x; LL y = q[i].y;
LL &S = q[i].sum; LL &fa = q[i].fa;
if (L[x] < L[y]) swap(x,y);
LL log;
for (log = 0; L[x] - (1< 0; ++log);
for (j = log; j >= 0; j--)
if (L[x] - (1<= L[y]) {
S += sum[x][j];
x = anc[x][j];
}
if (x == y) {
fa = y;
return;
}
for (j = log; j >= 0; j--)
if (anc[x][j] != anc[y][j]) {
S += sum[x][j] + sum[y][j];
x = anc[x][j]; y = anc[y][j];
}
S += sum[x][0] + sum[y][0];
fa = anc[x][0];
}
bool Judge(int now)
{
memset(vis,0,sizeof(vis));
memset(Mark,0,sizeof(Mark));
LL tot = 0,Max = 0;
for (i = 1; i <= m; i++)
if (q[i].sum > now) {
++Mark[q[i].x]; ++Mark[q[i].y];
Mark[q[i].fa] -= 2;
++tot;
Max = max(Max,q[i].sum);
}
memset(pass,0,sizeof(pass));
for (int l = 0; l < Last.size(); l++) qu.push(Last[l]);
while (!qu.empty()) {
LL k = qu.front(); qu.pop();
vis[Fa[k]] += Mark[k];
Mark[anc[k][0]] += Mark[k];
k = anc[k][0];
++pass[k];
if (pass[k] == du[k]) qu.push(k);
}
LL tmp = 0;
for (i = 1; i < n; i++)
if (vis[i] == tot)
tmp = max(tmp,t[i]);
return Max - tmp <= now;
}
int main()
{
cin >> n >> m;
memset(anc,-1,sizeof(anc));
for (i = 1; i < n; i++) {
LL x,y,w;
scanf("%d%d%d",&x,&y,&w);
v[x].push_back((E){y,w,i});
v[y].push_back((E){x,w,i});
t[i] = w;
}
L[1] = 1; Bfs(1);
LCA_pre();
for (i = 1; i <= m; i++) {
scanf("%d%d",&q[i].x,&q[i].y);
solve();
}
int l = -1,r = 3E8 + 30;
while (r - l > 1) {
LL mid = (l+r) >> 1;
if (Judge(mid)) r = mid;
else l = mid;
}
if (Judge(l)) cout << l;
else cout << r;
return 0;
}