Test 4 for NOIP- Result for Day3(误)

头大

这个暑假完就要去搞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 2333333
using 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,了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值