Test 9 for NOIP- Result for Day1

来源:互联网 发布:centos 7如何安装rpm包 编辑:程序博客网 时间:2024/05/16 09:28

头大

这个暑假完就要去搞NOIP了。。。

暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。


出题人神奇的把NOI的题强行改成了NOIP的题,还强行说T1很简单,更气人的是最后看了题解发现T1还真的那么简单。
随机大法好。orz
T2思路没对,T3第二遍DFS没想对orz。

Day1 (20/300)

T1 举办比赛 (20/100)

题目描述
Mstdream举办了一场抢答比赛!
这场抢答比赛有n支队伍参赛,第i支队伍将会被分配一个随机值si
每一个问题,si值较小的队伍会拥有优先发言权,于是Mstdream想知道所有队伍最小
的si值,以便统计
但是,由于各种各样的原因,一些队伍的si值会变化,Mstdream想让你帮忙,对于每
次修改后求出所有队伍中最小的si值
由于队伍实在太多了!我们将采用数据生成的方式读入数据
我们将给出n,m,x0,x1,a,b,c七个数,对于c++语言,我们将采用如下读入
你可以使用这份代码,也可以不使用

#define uint unsigned int uint x0,x1,a,b,c,n,m; uint now=1,tot=0; uint s[10000010]; uint nxt(){   uint t=x0*a+x1*b+c;   x0=x1;   x1=t;   return x0>>2; } int main(){ std::cin>>n>>m>>x0>>x1>>a>>b>>c;   for(int i=0;i<n;i++){   s[i]=2147483647;   }   for(int i=1;i<=m;i++){   int f=nxt();   int g=nxt();   int ps=f%n;   s[ps]=g;//此处是修改   uint ans=0;   //…..此处需要你求出s[0]到s[n-1]的最小值,并且存在ans当中   now*=10099;   tot+=now*ans;   }   std::cout<<tot<<std::endl; } 

根据相关理论,nxt()函数是随机的。

Input
7个数n,m,x0,x1,a,b,c

Output
一个数,即程序中的tot值

Sample Input
5 5 1 2 3 4 5

Sample Output
3818396440

Sample Input
10000000 10000000 555 888 777 666 12345

Sample Output
4134418848

范围
10% n,m<=1000
40% n,m,<=100000
100% n<=10000000,m<=50000000
保证x0,x1,a,b,c在unsigned int范围内

据出题人说这道题一般别人都会打线段树之类的。。。我会告诉你我用的单调队列吗。。。
20分就这么来的。

最后出题人说事实上按题意来讲最小值最多改变5次左右。。也就是判断一下再搜索一下就行了。。
然后liuyuwei上来又讲了几个随机大法的例子,什么随机n个数求最大最小值一般直接暴力从中间向两侧枚举之类的。

。。头一次发现随机大法还可以这么玩

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>using namespace std;#define uint unsigned int uint x0,x1,a,b,c,n,m,head=0,tail=0; uint now=1,tot=0; uint s[10000010]; inline unsigned int read(){    unsigned int i=0;    char ch;    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';    return i;}inline uint nxt(){   uint t=x0*a+x1*b+c;   x0=x1;   x1=t;   return x0>>2; } uint loc=0;uint minn=2147483647;signed main(){   //freopen("contest.in","r",stdin);  //freopen("contest.out","w",stdout);   ios::sync_with_stdio(0);cin.tie(0);  n=read();m=read();  x0=read();x1=read();  a=read();b=read();c=read();  for(int i=0;i<n;i++){   s[i]=2147483647;   }   for(int i=1;i<=m;i++){   int f=nxt();   int g=nxt();   int ps=f%n;   //此处是修改   if(g<minn){loc=ps;minn=g;s[ps]=g;}  else{    s[ps]=g;    if(ps==loc)    {        loc = min_element(s,s+n)-s;        minn = s[loc];    }  }  now*=10099;   tot+=now*minn;   }   cout<<tot<<endl; } 

随机大法好,不说别的orz

T2 疯狂的01串

题目描述
szzq有两个01字符串
有一天,他想把两个01字符串变得一样
szzq请来了Mstdream,请他用正好k步,每次改变m个数位将第一个字符串改变为第
二个字符串
改变一个数位的定义是将这一位异或1
Mstdream很快完成了任务
szzq又让Mstdream算出有多少种方案做到这一点,这下Mstdream不会了
请帮助Mstdream完成任务
当两种方案至少有一步中改变的至少有一位不同,我们认为两种方案是不同的

输入格式
第一行n,k,m
第二行 一个长为n的01串
第三行 一个长为n的01串

输出格式
一个数,代表方案数对1000000009取模后的结果

Sample Input
3 2 1
100
001

Sample Output
2
Hint
100->101->001
100->000->001

数据规模
30%数据满足1 ≤ n ≤ 5, 0 ≤ k≤ 2,0 ≤ m ≤ n
100%数据满足 1 ≤ n ≤ 100, 0 ≤ k≤ 100, 0 ≤ m ≤ n

最后30分钟做的,想到了与题解类似的但最后推公式推错了,没考虑用组合数,乱搞搞死了。
还得加强Dp的练习。

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<iomanip>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;int n,k,m,tot=0;long long f[105][105],c[105][105];char s[105],t[105];const int nod=1000000009;void pre(){    for(int i=0;i<=n;i++)c[i][0]=1;    for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)        c[i][j] = (c[i-1][j] + c[i-1][j-1])%nod;}int main(){    cin >> n >> k >> m;    scanf("%s%s",s,t);    for(int i=0;i<n;i++)      if(s[i]!=t[i])        tot++;    pre();  f[0][tot]=1;    //   j 取 l   个     for(int i=0;i<k;i++)    // n-j 取 m-l 个         for(int j=0;j<=n;j++)            for(int l=0;l<=m;l++) //f[i][j]:  i:已经替换的个数;  j:剩余的不同的;                if(j-l+m-l<=n)    //?????????                    f[i+1][j-l+m-l]+=(long long)(f[i][j]*c[j][l]%nod*c[n-j][m-l])%nod,                     f[i+1][j-l+m-l]%=nod;     cout << f[k][0] <<endl;}

T3 树

题目描述
Mstdream经营着一个国家!
这个国家的道路系统很奇怪,由n个城市和n-1条边构成,1号点为首都,每条边长度
均为1
显然,Mstdream的国家交通很堵塞,特别是首都人民,苦不堪言
终于,Mstdream决定修一条长度为1的道路!这条道路将连通首都以及另一个城市
由于修建道路成本巨大,Mstdream 联系到你,希望你能决定这条道路连接的另外一个
城市,使得首都到所有城市的最短距离之和最小

输入格式
第一行一个整数n,代表节点的数量
后面n-1行,每行两个数u v,表示u到v有一条边
数据保证给出的图是一棵树
输出格式
一个数,代表首都到所有城市的最短距离之和

Sample Input
6
1 2
2 3
3 4
3 5
3 6

Sample Output
8

Hint
选择3号点
d(1, 1) + d(1, 2) + d(1, 3) + d(1, 4) + d(1, 5) + d(1, 6) = 0 + 1 + 1 + 2 + 2 + 2 =
8

数据规模
对于30%数据 n<=200
对于50%数据 n<=2000
对于100%数据 n<=100000
保证答案在32有符号整数范围内

第一遍DFS和大佬想的差不多,但第二遍DFS就瓜起了,推了40分钟公式最后推出个不伦不类的玩意,GG。

感谢大佬zjj(?)的代码,等会重打。

STD.CPP

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<queue>#define uint unsigned int using namespace std;int getint(){    int i=0 ,f=1;char c;    for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());    if(c=='-')f=-1,c=getchar();    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';    return i*f;}const int N=1e5+5;int n;int totdis,ans;int tot,first[N],next[N<<1],to[N<<1];int dep[N],fa[N],size[N],son[N];void add(int x,int y){    next[++tot]=first[x],first[x]=tot,to[tot]=y;}void dfs(int u){    size[u]=1;    for(int e=first[u];e;e=next[e])    {        int v=to[e];        if(v==fa[u])continue;        fa[v]=u;        dep[v]=dep[u]+1;//子树的深度         totdis+=dep[v];//不加边时的答案         dfs(v);        size[u]+=size[v];//子树拥有的节点数     }}void solve(int u,int f,int cnt,int delta)//。。觉得cnt和delta的意义不好说。。 应该就是两个辅助计数的数 {    if(dep[u]>=2)//只有dep(u)>2时加的边才有实际意义     {        delta+=size[u]-cnt;//size[v]一段对答案的贡献减一,因为距离新更新的点更近。①,详见下面 ②↓↓↓         ans=min(ans,totdis-delta);    }    if((dep[u]+1)/2>dep[f])//顶点连接的另外一个点(u)最多影响到他与顶点(1)之间的中点(f)所在的子树     {        f=son[f];        if(dep[u]>2)cnt-=size[f]-size[son[f]]; //u点前移,f随之前移,cnt更新,结果加上(pre)f所在子树的贡献与当前f所在子树的贡献之差。     }    for(int e=first[u];e;e=next[e])    {        int v=to[e];        if(v==fa[u])continue;        int tmp1=cnt,tmp2=delta;//记忆化搜索,for循环的第二步是基于之前的cnt与delta而不是DFS后的。        if(dep[u]>=2)cnt+=size[u]-size[v];//② 记录如果连边连到v所造成的差值,size[u]-size[v]一段的点贡献加一,因为新更新的点在他们之前         son[u]=v;        solve(v,f,cnt,delta);        if(dep[u]>=2)cnt=tmp1,delta=tmp2;//记忆化搜索,for循环的第二步是基于之前的cnt与delta而不是DFS后的。     }}int main(){    int x,y;    n=getint();    for(int i=1;i<n;i++)    {        x=getint(),y=getint();        add(x,y),add(y,x);    }    dfs(1);    ans=totdis;    solve(1,1,0,0);    cout<<ans;    return 0;}

感想:

学会推公式,推的要准,不然全挂,还有试数据多试几个,试个5个再说。

原创粉丝点击