头大
这个暑假完就要去搞NOIP了。。。
暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。
。。。别问我为什么我没有给Day1的题目。。。三道水题我被坑的只有10分。。。。。。本来可以100多的。。
要不是这次几乎集体划水我的这个分只可能算垫底。(No.8)
Day2 (70/300)
T1 Hello(30/100)
题目背景
SOURCE:NOIP2015-SHY-1
题目描述
Alice 和 Bob 有一个长度为2n的数。现在他们要在这个数字上玩游戏。他们分别要从 2n 个位中取出 n 个位组成自己的幸运值。每一回合,Alice 或 Bob 把数字最左边的那一位拿来放在自己幸运值
的最末位。在第 i 轮操作过后,被选取的数位(原数的第i位)会从原数中消失。现在 Alice 和 Bob 想要使得他们两个幸运值的和尽可能大。请求出这个值。
输入格式
第一行一个整数 n ,意为幸运值的长度。
第二行一个长度为 2n 的数字,表示原数。
输出格式
一个整数为幸运值的和的最大值。
样例数据 1
输入 [复制]
2
1234
输出
46
备注
【样例说明】
Alice 取 1、2 位。Bob 取 3、4 位。幸运值分别为 12 和 34 ,和为 46 。
【数据范围】
对 30% 的输入数据 : n≤10;
对 100% 的输入数据 : n≤18,原数与幸运值均允许前缀 0 的存在。
MY.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
int n,num[40],pos[40],ans[20];
int alice[20],bob[20],alicei=0,bobi=0;
char c;
bool visit[40];
struct node{
int num;
int pos;
}deal[40];
bool comp(node a,node b)
{
if(a.num==b.num) return a.pos < b.pos;
return a.num > b.num;
}
void find()
{
for(int i=1;i<=2*n;i++)
{
if(deal[i].pos<=alicei+n+1 && alicei<deal[i].pos && !visit[deal[i].pos] )
{
visit[deal[i].pos] = true;
if(bobi<=n)
for(int j=alicei+1;j<=deal[i].pos;j++)
{
if(!visit[j])
{
bobi += 1;
visit[j] = true;
bob[bobi] = num[j];
}
}
alicei += 1;
alice[alicei] = deal[i].num;
}
}
}
int main()
{
freopen("hello.in","r",stdin);
freopen("hello.out","w",stdout);
cin >> n;
for(int i=1;i<=2*n;i++)
{
cin >> c;
num[i] = c-'0';
deal[i].num = num[i];
deal[i].pos = i;
}
sort(deal+1,deal+2*n+1,comp);
find();
if(alicei!=n)
for(int i=1;i<=2*n,alicei<n;i++)
if(!visit[i])
{
alicei+=1;
alice[alicei] = num[i];
}
if(bobi!=n)
for(int i=1;i<=2*n,bobi<n;i++)
if(!visit[i])
{
bobi+=1;
bob[bobi] = num[i];
}
for(int i=1;i<=n;i++)
{
ans[i-1] += (alice[i]+bob[i])/10;
ans[i] += (alice[i]+bob[i])%10;
}
if(ans[0]) cout << ans[0];
for(int i=1;i<=n;i++) cout << ans[i];
}
题解却mdzz又是动态规划,而且也是不难想的那种,害得我还慢慢推了半天只过了30%。。。周日必须补动态规划了(其它时间我在预习高二。。)
STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
int n,num[40];
unsigned long long dp[20][20];
char c;
int main()
{
freopen("hello.in","r",stdin);
freopen("hello.out","w",stdout);
memset(dp,0,sizeof(dp));
cin >> n;
for(int i=1;i<=2*n;i++)
{
cin >> c;
num[i] = c-'0';
if(i<=n)
{
dp[i][0] = num[i-1]*10 + num[i];
dp[0][i] = num[i-1]*10 + num[i];
}
}
dp[0][0] = 0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
{
if(i!=n)dp[i+1][j] = max(dp[i+1][j] , dp[i][j] + num[i+j+1]*(long long)pow(10,n-i-1));
if(j!=n)dp[i][j+1] = max(dp[i][j+1] , dp[i][j] + num[i+j+1]*(long long)pow(10,n-j-1));
}
cout << dp[n][n];
}
这题的动归实际上更简单。。。
T2 Rect(10/100)
题目背景
SOURCE:NOIP2015-SHY-1
题目描述
给定一个由数字(0-9)构成的字符串 s 。我们可以由此定义出 size(s) * size(s) 大小的矩阵 b ,其中 b[i][j] = s[i] * s[j] ;请问在这个矩阵 b 中,有多少子矩形满足其中的 b[i][j] 的和为另一个给定的数字 a 。
输入格式
第一行一个整数 a 。
第二行字符串 s 。
输出格式
输出一个整数表示满足条件的子矩形数。
样例数据 1
输入 [复制]
10
12345
输出
6
备注
【样例说明】
b矩阵为:
01 02 03 04 05
02 04 06 08 10
03 06 09 12 15
04 08 12 16 20
05 10 15 20 25
和为10的子矩形有:
(1)
01 02 03 04
(2)
01
02
03
04
(3)
04 06
(4)
04
06
(5)
10
(6)
10
以上共六个。
【数据范围】
对 10% 的输入数据 :size(s)≤10 ;
对 30% 的输入数据 :size(s)≤100 ;
对 100% 的输入数据 :0≤a≤1000000000,size(s)≤4000 。
MY.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
int n,ni;
long long ans=0;
unsigned long long ai;
unsigned long long bx[4005],by[4005];
char c[4005];
int main()
{
freopen("rect.in","r",stdin);
freopen("rect.out","w",stdout);
cin >> ai;
gets(c);
gets(c);
n = strlen(c);
int flag = 1;
for(int i=0;i<n;i++)
{
bx[i+1] = bx[i]+c[i]-'0';
by[i+1] = by[i]+c[i]-'0';
}
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
for(int a=i;a<=n;a++)
for(int b=a;b<=n;b++)
if((bx[j]-bx[i-1])*(bx[b]-bx[a])==ai)
ans += 1;
cout << ans;
}
连打暴力后来发现都打错了害得30分的暴力分只得了十分。。。而且题解也不难想。。。我的脑子停机了吗。。
枚举横行与A相除得除数,再在纵行里枚举。就能避免n^4的时间复杂度。
STD.CPP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
using namespace std;
char s[4005];
int n;
int sum[4005][4005],cnt[40005];
int aim,ans,all;
int main()
{
//freopen("lx.txt","r",stdin);
cin>>aim>>s+1;
n=strlen(s+1);
for(int i=1;i<=n;++i)
{
long long res=0;
for(int j=i;j<=n;++j)
{
res+=s[j]-'0';
sum[i][j]=res;
cnt[res]++;
all++;
}
}
for(int i=1;i<=n;++i)
for(int j=i;j<=n;++j)
{
if(!sum[i][j])
{
if(!aim)ans+=all;
}
else
if(aim%sum[i][j]==0&&aim/sum[i][j]<4005*9)
ans+=cnt[aim/sum[i][j]];
}
cout<<ans<<endl;
return 0;
}
T3 Shortest(30/100)
题目背景
SOURCE:NOIP2015-SHY-3
题目描述
给定一张 n 个点的有向带权完全图,和一个数组 a[] ,请按顺序删除数组中的点,请求出在删除点 a[i] 以前,所有未删除点对之间的最短路的值的和。
输入格式
第一行一个整数 n ,表示点数;
接下来 n 行,每行 n 个数构成邻接矩阵,描述每条边的权值,保证 i 号点到 i 号点的权值为 0 ;
最后一行 n 个小于等于 n 的不同的数,描述数组 a[]。
输出格式
输出 1 行 n 个数,表示答案。
样例数据 1
输入 [复制]
4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
输出
17 23 404 0
备注
【数据范围】
对 30% 的输入数据 :1≤n≤10 ;
对 100% 的输入数据 :1≤n≤500;0<权值≤100000 。
MY.CPP
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int n, s, cnt = 0;
int stack[200050], hash[70000], check[70000];
char c[5], num[20];
void cint(int aq,int cnt)
{
int ans=0,i;
for(i=1;i<=cnt;i++)
{
if(hash[stack[i]])
{
int h1 = stack[i];
int h2 = aq;
if((h1&h2)==stack[i])
ans += hash[stack[i]];
}
}
cout << ans << endl;
}
bool comp(int a,int b)
{
return a>b;
}
int init(int cnt,int flag)
{
sort(stack+1,stack+cnt+1,comp);
if(flag) cnt-=1;
for(int i=1;i<=cnt;i++)
check[stack[i]] = i;
return cnt;
}
int main()
{
int y=0;
cin >> n;
while(n--)
{
int flag=0;
scanf("%s",c); cin >> s;
if(c[0]=='a') {hash[s]+=1;if(hash[s]==1)stack[++cnt]=s;}
else if(c[0]=='d') {hash[s]-=1;if(hash[s]==0)stack[check[s]]=0,check[s]=0,flag = 1;}
else if(c[0]=='c') {cint(s,cnt);y+=1;}
cnt = init(cnt,flag);
}
}
这道题最恶心的是我用SPFA打了半天才能的暴力分,而最开始一直鄙视的Floyed确是正确解法。。。
。。。。。。
动态规划得好好补补了orz。
STD.CPP
//卧槽是Floyed
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
int n;
long long a[505];
long long f[505][505],ans[505];
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin >> f[i][j];
for(int i=1;i<=n;i++)
cin >> a[i];
for(int i=n;i>=1;i--)
{
for(int j=n;j>i;j--)
for(int k=n;k>i;k--)
{
f[a[i]][a[j]] = min(f[a[i]][a[j]],f[a[i]][a[k]]+f[a[k]][a[j]]);
f[a[j]][a[i]] = min(f[a[j]][a[i]],f[a[j]][a[k]]+f[a[k]][a[i]]);
}
for(int j=n;j>i;j--)
for(int k=n;k>i;k--)
f[a[j]][a[k]] = min(f[a[j]][a[k]],f[a[j]][a[i]]+f[a[i]][a[k]]);
for(int j=n;j>=i;j--)
for(int k=n;k>=i;k--)
ans[i] += f[a[j]][a[k]];
}
for(int i=1;i<=n;i++) cout << ans[i] << " ";
}
代码同样短的吓人。
好,好,学,习,动,态,规,划。