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