Test 4 for NOIP- Result for Day3(误)

来源:互联网 发布:软件安装手册 编辑:程序博客网 时间:2024/06/05 21:57

头大

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

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


???曾老说好的周五周六不考试呢系列???
。。。这次真的无语。。本来120的总分最后败在了scanf和if,else手里。。。。(零蛋)
。所以总分按改了后的算吧(滑稽)

Day3(误)(120/300)

T1 Matrix(100/100)

题目背景
SOURCE:NOIP2016-RZZ-1

题目描述
给出两个 N×N 的矩阵 A、B,矩阵每行每列标号 0~N-1 。

现在要在这两个矩阵上依次进行 Q 次修改操作,两种操作描述如下:

A i j K ,将 Ai,j 的值修改为 K 。
B i j K ,将 Bi,j 的值修改为 K 。
在每一次修改操作进行后,输出矩阵 AB(这两个矩阵的乘积矩阵)中每个位置元素的权值之和。(矩阵的乘积自己查)

输入格式
第一行,一个正整数 N ,表示矩阵的大小。
接下来 N 行,每行 N 个整数,描述矩阵 A 。
接下来 N 行,每行 N 个整数,描述矩阵 B 。
接下来一行,一个正整数 Q ,表示操作次数。
接下来 Q 行,每行描述一个操作,格式如题面所示。

输出格式
输出 Q 行,每行一个整数,表示这次操作完成后的答案。

样例数据 1
输入  [复制]

2
1 2
3 4
4 3
2 1
3
A 1 1 2
B 0 1 3
A 0 0 10
输出

40
40
103
备注
【数据规模与约定】
对于 10% 的数据,N = 1。
对于 30% 的数据,N,Q≤10。
对于 80% 的数据,1≤N≤100,|Ai,j|,|Bi,j|≤10。
对于 100% 的数据,1≤N≤1000,1≤Q≤105,|Aij|,|Bi,j|≤1000。

答案和表达一模一样,就最后我为了提一下速度没记住cin的oi优化用了scanf。。。然后gg。
所以以后打死也不用scanf了→_→。很生气。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;char c;int n,y,q;long long a[1005],b[1005],sum=0,x,d;long long mapa[1005][1005],mapb[1005][1005];int main(){    freopen("matrix.in","r",stdin);    freopen("matrix.out","w",stdout);    scanf("%d",&n);    for(int i=0;i<n;i++)      for(int j=0;j<n;j++)      {        scanf("%d",&x);        a[j] += x;        mapa[i][j] = x;      }    for(int i=0;i<n;i++)      for(int j=0;j<n;j++)      {        scanf("%d",&x);        b[i] += x;        mapb[i][j] = x;        sum += mapb[i][j]*a[i];      }    cin >> q;    while(q--)    {        scanf("%c%d%d%d",&c,&x,&y,&d);        scanf("%c%d%d%d",&c,&x,&y,&d); //<=就是这里卡了很久        if(c=='A')          {            sum += (d-mapa[x][y])*b[y];            a[x] += (d-mapa[x][y]);            mapa[x][y] = d;        }        else            {            sum += (d-mapb[x][y])*a[x];            b[y] += (d-mapb[x][y]);            mapb[x][y] = d;        }        cout << sum << endl;    }    return 0;}

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;char c;int n,y,q;long long a[1005],b[1005],sum=0,x,d;long long mapa[1005][1005],mapb[1005][1005];int main(){    ios::sync_with_stdio(false);    cin.tie(NULL);    cin >> n;    for(int i=0;i<n;i++)      for(int j=0;j<n;j++)      {        cin >> x;        a[j] += x;        mapa[i][j] = x;      }    for(int i=0;i<n;i++)      for(int j=0;j<n;j++)      {        cin >> x;        b[i] += x;        mapb[i][j] = x;        sum += mapb[i][j]*a[i];      }    cin >> q;    while(q--)    {        cin >> c >> x >> y >> d;        if(c=='A')          {            sum += (d-mapa[x][y])*b[y];            a[y] += (d-mapa[x][y]);            mapa[x][y] = d;        }        else            {            sum += (d-mapb[x][y])*a[x];            b[x] += (d-mapb[x][y]);            mapb[x][y] = d;        }        cout << sum << endl;    }}

这题的动归实际上很简单。。。

T2 Roads(0/100)

题目背景
SOURCE:NOIP2016-RZZ-1

题目描述
有 N 个城市,这些城市通过 M 条无向边互相连通,每条边有一个权值 Ci ,表示这条边的长度为 2^(Ci) ,没有两条边的长度是相同的。

设 d(i,j)为城市 i 到城市 j 的最短路长度,求:
这里写图片描述
答案以二进制输出。

输入格式
第一行,两个正整数 N ,M 。
接下来 M 行,每行三个正整数 Ai,Bi,Ci ,表示城市 Ai,Bi 间有一条权值为 Ci 的无向边。

输出格式
输出一个二进制数,表示所有无序点对间的最短路长度之和(即问题描述中的式子)。

样例数据 1
输入  [复制]

5 6
1 3 5
4 5 0
2 1 3
3 2 1
4 3 4
4 2 2
输出

1000100
备注
【样例解释】

这里写图片描述

【数据规模与约定】
对于 30% 的数据,N,M≤50。
对于 60% 的数据,N,M≤100。
对于 80% 的数据,N≤2000;M≤10000。
对于 100% 的数据,1≤N≤105;1≤M≤2×105;1≤Ai,Bi≤N,Ai≠Bi,0≤Ci<M。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;bool c[10000500];int n,m,x,y,z;const int kkk=100010;struct node{    int u,v,val,next;}side[2*kkk];int cnt=0,first[kkk];inline void addedge(int u,int v,int val){    cnt += 1;    side[cnt].u = u;    side[cnt].v = v;    side[cnt].val = val;    side[cnt].next = first[u];    first[u] = cnt;}bool visit[kkk];long long dis[kkk];inline long long dij(int s){    memset(dis,127,sizeof(dis));    memset(visit,false,sizeof(visit));    priority_queue< pair<int,int> >que;    que.push(make_pair(0,s));    dis[s] = 0;    for(int i=1;i<=n;i++)    {        pair<int,int> k = que.top();        que.pop();        visit[k.second] = true;        for(int j=first[k.second];j;j=side[j].next)        {            int v = side[j].v;            if(!visit[v] && dis[v]>dis[k.second]+pow(2,side[j].val))            {                dis[v] = dis[k.second]+pow(2,side[j].val);                que.push(make_pair(-dis[v],v));            }        }    }    long long hh=0;    for(int i=s+1;i<=n;i++)        hh += dis[i];    return hh;}int main(){    cin >> n >> m;    for(int i=1;i<=m;i++)    {        cin >> x >> y >> z;        addedge(x,y,z);        addedge(y,x,z);    }    long long ans=0;    for(int i=1;i<=n;i++)      ans += dij(i);    int ct = 0;    while(ans)    {        ct += 1;        c[ct] = ans%2;        ans = (ans-ans%2)/2;    }    for(int i=ct;i>=1;i--)  cout << c[i];    return 0;}

显然这道题要用高精度。
当时我看到我能试着把T3多得一点分想直接暴算不开高精度节约时间。。。最后内存定义BOOL数组太大了挂掉,,而且答案全部都要用高精度。还要用我还没怎么看的最小生成树。
好吧我认输,顺便把最小生成树补了。

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<cmath>using namespace std;const int maxx = 100005;int n,m,u,v,k,tot;int fa[maxx],a[2*maxx],b[2*maxx];int size[maxx],first[maxx];long long ans[3*maxx];bool visit[maxx];struct node{    int u,v,val,next;}side[2*maxx];int getfa(int x){return (fa[x]==x?x:fa[x]=getfa(fa[x]));}void dfs(int x){    visit[x] = true;    size[x] = 1;    for(int i=first[x];i;i=side[i].next)     {        int v = side[i].v;        if(!visit[v])           {            dfs(v);            ans[side[i].val] += (long long) size[v]*(n-size[v]);            size[x] += size[v];        }    }}void addedge(int u,int v,int k){    tot++;    side[tot].u = u;    side[tot].v = v;    side[tot].val = k;    side[tot].next = first[u];    first[u] = tot;}int main(){    cin >> n >> m;    for(int i=1;i<=n;i++)   fa[i] = i;    for(int i=1;i<=m;i++)   cin>>u>>v>>k,a[k]=u,b[k]=v;    for(int i=0;i<m;i++)    {        u = a[i];   v = b[i];        if(getfa(u)!=getfa(v))        {            fa[getfa(u)] = v;            addedge(u,v,i);            addedge(v,u,i);        }    }    dfs(1);    int jud;    for(int i=0;i<=m+100;++i)   ans[i+1]+=ans[i]/2,ans[i]%=2;    for(int i=m+100;i>=1;i--)   if(ans[i]) {jud=i;break;}    for(int i=jud;i>=0;i--) cout << ans[i];    cout << endl;}

T3 Grid(20/100)

题目背景
SOURCE:NOIP2016-RZZ-1 T3

题目描述
有一个 2×N 的矩阵,矩阵的每个位置上都是一个英文小写字符。

现在需要从某一个位置开始,每次可以移动到一个没有到过的相邻位置,即从 (i,j) 可以移动到 (i-1,j)(i+1,j)(i,j-1)(i,j+1) (要求该位置在矩阵上且之前没有到过)。

从选取的起点开始,经过 2N-1 次移动后,将会走过矩阵的每一个位置,将移动经过的格子依次取出来就得到了一个长度为 2N 的串。

可以任意选择起点和终点,任意选择移动方案,求能得到多少种不同的串。

输入格式
输入第一行,一个正整数 N 。
接下来两行,每行一个由英文小写字符组成的字符串,描述这个矩阵。

输出格式
输出一行一个整数,表示能得到的串的总数。

样例数据 1
输入  [复制]

1
a
a
输出

1
样例数据 2
输入  [复制]

3
dab
abd
输出

8
样例数据 3
输入  [复制]

5
ababa
babab
输出

2
备注
【样例2说明】
能得到的字符串有:abdbad, adabdb, badabd, bdbada, dababd, dabdba, dbabad, dbadab。

【数据规模与约定】
对于 20% 的数据,N≤5。
对于 60% 的数据,N≤50。
对于 100% 的数据,N≤600。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;const int nod = 1000007;int map[5][605];int n,dp[5][605],ans;bool visit[5][605],exist[nod];int dir[5] = {0,1,-1,0,0};void dfs(int x,int y,int step,long long hash1,long long hash2){    step += 1;    visit[x][y] = true;    hash1 = (hash1*29 + map[x][y]+1)%nod;    hash2 = (hash2*31 + map[x][y]+1)%nod;    if(step<2*n)      for(int i=1;i<=4;i++)      {                // <= 一开始这里没有        if(!visit[x+dir[i]][y-dir[5-i]]&&dp[x+dir[i]][y-dir[5-i]])          dfs(x+dir[i],y-dir[5-i],step,hash1,hash2);      }                // <= 一开始这里没有    else if(step==2*n)    {        if(!exist[hash1]&&!exist[hash2])        {          exist[hash1] = true;  exist[hash2] = true;          ans+=1;        }    }    visit[x][y] = false;}int main(){    char c;    cin >> n;    for(int i=1;i<=2;i++)      for(int j=1;j<=n;j++)      {        cin >> c;        map[i][j] = c-'a'+1;        dp[i][j] = 1;      }    if(n==1)    {cout << 1 << endl;return 0;}    for(int i=1;i<=2;i++)      for(int j=1;j<=n;j++)      {        dfs(i,j,0,0,0);      }    cout << ans << endl;    return 0;}

被if又摆了一道。。。如果不加大括号的话else是与第二个if达成关系而不是和第一个。。。20暴力分没了。。。(预估40+)
以后有if一定要加大括号。我就不信了。
题解是谜一般的字符串哈希。。。还得研究研究简直看的眼花缭乱。

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#define mod 1000000007#define hash1 2333#define hash2 23333#define spi 2333333using namespace std;inline int read(){    int i=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch);ch=getchar())        if(ch=='-') f=-1;    for(;isdigit(ch);ch=getchar())        i=(i<<3)+(i<<1)+(ch^48);    return i*f;}char s[3][700];long long l[3][700],l2[3][700],pow1[20000],pow2[20000],pre,pre2,num[6000600],num2[6000600];int n,first[spi],nxt[6000600],tot,k;void rotate(long long x,long long x2){    int i,y=x%spi;    for(int i=first[y];i;i=nxt[i])        if(num[i]==x&&num2[i]==x2) return ;    num[++tot]=x;num2[tot]=x2;    nxt[tot]=first[y];first[y]=tot;    return ;}signed main(){ //...下面很大一坨都只是在搞谜一般的字符串哈希而已...    pow1[0]=pow2[0]=1;    for(int i=1;i<=1300;++i)        pow1[i]=pow1[i-1]*hash1,pow2[i]=(pow2[i-1]*hash2)%mod;    n=read();    scanf("%s%s",s[1]+1,s[2]+1);    tot=0;    for(int form=1;form<=4;++form){        for(int i=1;i<=n;++i){            l[1][i] = l[2][i] = l2[1][i] = l2[2][i]=0;            for(int j=i;j>=1;--j) l[1][i]=l[1][i]*hash1+s[1][j];            for(int j=1;j<=i;++j) l[1][i]=l[1][i]*hash1+s[2][j];            for(int j=i;j>=1;--j) l[2][i]=l[2][i]*hash1+s[2][j];            for(int j=1;j<=i;++j) l[2][i]=l[2][i]*hash1+s[1][j];            for(int j=i;j>=1;--j) l2[1][i]=(l2[1][i]*hash2+s[1][j])%mod;            for(int j=1;j<=i;++j) l2[1][i]=(l2[1][i]*hash2+s[2][j])%mod;            for(int j=i;j>=1;--j) l2[2][i]=(l2[2][i]*hash2+s[2][j])%mod;            for(int j=1;j<=i;++j) l2[2][i]=(l2[2][i]*hash2+s[1][j])%mod;        }        for(int i=1;i<=n;++i){            pre=pre2=0;            for(int j=i;j<=n;++j) pre=pre*hash1+s[1][j];            for(int j=n;j>=i;--j) pre=pre*hash1+s[2][j];            for(int j=i;j<=n;++j) pre2=(pre2*hash2+s[1][j])%mod;            for(int j=n;j>=i;--j) pre2=(pre2*hash2+s[2][j])%mod;            k=2;            for(int j=i;j>=1;--j){                rotate(pre*pow1[j+j-2]+l[k][j-1],(pre2*pow2[j+j-2]+l2[k][j-1])%mod); // <=这里开始解题                 pre=pre*hash1+s[k][j-1];                pre2=(pre2*hash2+s[k][j-1])%mod;                k=3-k;                pre=pre*hash1+s[k][j-1];                pre2=(pre2*hash2+s[k][j-1])%mod;            }        }        for(int i=1;i<=n;++i)            swap(s[1][i],s[2][i]);        if(form==2){            for(int i=1;i<=n/2;++i){                swap(s[1][i],s[1][n-i+1]);                swap(s[2][i],s[2][n-i+1]);            }        }    }    cout<<tot;    return 0;}

字符串哈希觉得快学不走了。。。还好没有再搞什么莫比乌斯反演之类的。。
以,后,打,死,也,不,用,s,c,a,n,f,了!!!

原创粉丝点击