头更大
这个9月完就要去集训搞NOIP了。。。
9月30天也就3次测试。。。为防万一我还是每次测试玩都写个总结。。
第一题苟住不说。
第二题。。出题人mmp说好的50分暴力呢??实际上只给了30。。
第三题。。本来用的Kruskal距离标答很近了。。但后面1小时脑子抽了只因为看到了连通块用Tarjan去了。。。智障。。。
还行所有做得起的题距离标答都很接近了,暴力也能(是)拿(变)到(简)分(单)了。。
tEST 2 (120/300)
Change
题目背景
SOURCE:NOIP2015-SHY-8
题目描述
我认为一个优美的字符串的任何大写字母总是在所有小写字母的前面。现在,请修改给定的字符串,使得它变得完美。
文章的字符保证是大写字母或小写字母,一次操作定义为把一个大写字母改成小写字母,或把一个小写字母改成大写字母。请求出最小操作次数。
输入格式
输入一个字符串。
输出格式
输出一个值表示最小操作次数。
样例数据 1
输入 [复制]
PRuvetSTAaYA
输出
5
备注
【样例说明】
aim string = PRuvetSTAaYA -> PRUVETSTAAYA
【数据范围】
对 50% 的输入数据 :1≤字符串长度≤1000
对 100% 的输入数据 :1≤字符串长度≤100000
。。纯裸的枚举。。
MY/STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
int n,bigal[100500],smlal[100500];
char c[100500];
int main()
{
//freopen("change.in","r",stdin);
//freopen("change.out","w",stdout);
scanf("%s",c); n = strlen(c);
memset(bigal,0,sizeof(bigal));
memset(smlal,0,sizeof(smlal));
for(int i=1;i<=n;i++)
{
smlal[i] = smlal[i-1];
bigal[i] = bigal[i-1];
if(c[i-1]>='a'&&c[i-1]<='z')smlal[i]++;
if(c[i-1]>='A'&&c[i-1]<='Z')bigal[i]++;
}
int ans = 999999999;
for(int i=0;i<=n;i++)
ans = min(ans,smlal[i]+bigal[n]-bigal[i]);
cout << ans;
}
Count(30/100)
题目背景
SOURCE:NOIP2015-SHY-8
题目描述
给定一个元素个数为 n 的整数数组 a 和 Q 个问题,每个问题有 x,y 两个参数,请统计共有多少个整数 K 满足 K 在 a[x]…a[y] 中出现了恰好 K 次。
输入格式
第一行两个整数 n,Q,表示数组 a 的元素个数和询问数;
接下来一行 n 给整数,描述数组 a ;
接下来 Q 行,每行两个数 xi,yi(1≤xi≤yi≤n),表示询问的左右边界。
输出格式
输出 Q 行,每行一个整数表示满足询问的 K 的个数。
样例数据 1
输入 [复制]
7 2
3 1 2 2 3 3 7
1 7
3 4
输出
3
1
备注
【样例说明】
Q1: 1、2、3 分别满足,所以共有 3 个数满足要求。
Q2: 2 满足,所以只有 1 个数满足要求。
【数据范围】
对 50% 的输入数据:1≤n,Q≤1000
对 100% 的输入数据:1≤n,Q≤100000,1≤a[i]≤109
MY.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
int n,q,x,y;
int a[100050];
int num[100050],act[100050],chk[100050];
int stk[100050];
int loc(int x,int pos)
{
int j;
j = x%100050;
while(chk[j]&&chk[j]!=x)j=(j+1)%100050;
act[j]=pos;
return j;
}
int main()
{
//freopen("count.in","r",stdin);
//freopen("count.out","w",stdout);
cin >> n >> q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=q;i++)
{
int cnt=0,ans=0;
cin >> x >> y;
memset(stk,0,sizeof(stk));
memset(num,0,sizeof(num));
for(int j=x;j<=y;j++)
{
if(a[j]>y-x+1)continue;
else{
int h = loc(a[j],j);
num[h]++;
if(num[h]==1)stk[++cnt]=h;
if(num[h]>a[j])num[h]=-99999;
}
}
for(int j=1;j<=cnt;j++)
if(num[stk[j]]==a[act[stk[j]]])ans+=1;
cout << ans << endl;
}
}
优雅的打了个暴力然而出题人恶心地给了50分。
正解是莫队算法(好像本来丧心病狂的出题人还想卡莫队?)据说莫队大法好(曾老推荐)(原来搞过失败了就没搞了),下来回去搞一搞。
就是分块然后暴力枚举。
STD.CPP
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
struct node{
int l,r,pos,id,ans;
}query[100010];
int n,q,a[100010],ti[100010];
int read()
{
int x=0;
char ch;
int f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
bool comp1(node a,node b)
{
if(a.id!=b.id) return a.id<b.id;
if(a.r!=b.r) return a.r<b.r;
return a.l<b.l;
}
bool comp2(node a,node b)
{
return a.pos<b.pos;
}
int main()
{
n=read();
q=read();
int sq=sqrt(n-1)+1;
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=q;++i)
{
query[i].l=read();
query[i].r=read();
query[i].id=(query[i].l-1)/sq;
query[i].pos=i;
}
sort(query+1,query+1+q,comp1);
int l=1,r=0;
int ans=0;
for(int i=1;i<=q;++i)
{
while(r<query[i].r)
{
++r;
if(a[r]<=100000)
{
ti[a[r]]++;
if(ti[a[r]]==a[r]) ans++;
if(ti[a[r]]==a[r]+1) ans--;
}
}
while(r>query[i].r)
{
if(a[r]<=100000)
{
ti[a[r]]--;
if(ti[a[r]]==a[r]) ans++;
if(ti[a[r]]==a[r]-1) ans--;
}
--r;
}
while(l<query[i].l)
{
if(a[l]<=100000)
{
ti[a[l]]--;
if(ti[a[l]]==a[l]) ans++;
if(ti[a[l]]==a[l]-1) ans--;
}
++l;
}
while(l>query[i].l)
{
--l;
if(a[l]<=100000)
{
ti[a[l]]++;
if(ti[a[l]]==a[l]) ans++;
if(ti[a[l]]==a[l]+1) ans--;
}
}
query[i].ans=ans;
}
sort(query+1,query+1+q,comp2);
for(int i=1;i<=q;++i)
cout<<query[i].ans<<endl;
return 0;
}
Road
题目背景
SOURCE:NOIP2015-SHY-8
题目描述
给出一张n个点,m条边的无向图,摧毁每条边都需要一定的体力,并且花费的体力值各不相同,给定图中两个点x,y(x≠y),每当(x,y)之间存在路径,就需要不断摧毁当前图中花费体力最少的一条边,直到该路径不联通。他定义cost(x,y)为摧毁(x,y)之间路径花费的体力和。
他想要求出以下这个结果:
其中 i,j∈n,并且i<j 。
输入格式
第一行两个整数 n,m ,表示点数和边数。
接下来 m 行,每行三个整数 x,y,z,表示 x 和 y 之间存在一条花费体力为 z 的无向边。
输出格式
输出一个整数表示所求结果。
样例数据 1
输入 [复制]
6 7
1 2 10
2 3 2
4 3 5
6 3 15
3 5 4
4 5 3
2 6 6
输出
256
备注
【数据范围】
对 50% 的输入数据 :1≤n≤100;1≤m≤1000
对 100% 的输入数据 :1≤n,m≤100000;1≤z≤100000
脑抽把可爱的Kruskal扔了去搞Tarjan我脑袋是被驴踢了??
好吧有一个原因是因为我没推出那个求得答案的公式。
STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
const int kkk = 100005;
const int nod = 1e9;
int n,m,cnt,size[kkk];
struct node{
int u,v,val;
}side[kkk];
bool comp(node a,node b){return a.val>b.val;}
bool visit[kkk];
int fa[100005];
int getfa(int x){if(x==fa[x])return x;fa[x]=getfa(fa[x]);return fa[x];}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
//freopen("road.in","r",stdin);
//freopen("road.out","w",stdout);
cin >> n >> m;
for(cnt=1;cnt<=m;cnt++)
{
int i,j;
cin >> i >> j >> side[cnt].val;
side[cnt].u = i;
side[cnt].v = j;
fa[i]=i; size[i]=1;
fa[j]=j; size[j]=1;
}
sort(side+1,side+cnt+1,comp);
long long ans=0,jud=0;
for(int i=1;i<=m;i++)
{
#define U getfa(side[i].u)
#define V getfa(side[i].v)
if(getfa(side[i].u)!=getfa(side[i].v))//就是这个if(){}里面的公式没推出来。连通块运用还不熟。
{
jud -= (long long)size[U]*(long long)(size[U]-1)/2;
jud -= (long long)size[V]*(long long)(size[V]-1)/2;
size[U] += size[V];
jud += (long long)size[U]*(long long)(size[U]-1)/2;
fa[getfa(side[i].v)] = side[i].u;
}
ans += jud*(long long)side[i].val;
ans %= nod;
}
cout << ans;
}
感想
T1现在能(变)苟(简)住(单)了。。T2,T3的暴力还要学学,打得好暴力,定能出奇迹。
要补补二分,Dp和网络流了。。
可喜可贺的是10年内战算是基本结束了以后可以有更多时间在家里以及学校里搞事情了。这里感谢某陈姓教师