1. 程式人生 > 實用技巧 >COCI 2012/2013 Contest #6

COCI 2012/2013 Contest #6

Problems-PDF

快讀異或沒注意優先順序我是傻逼。


BAKA

小模擬一下就完事了。

#include<bits/stdc++.h>
using namespace std;
map<char,int> p;
int ans=0;
int main()
{
	p['A']=2,p['B']=2,p['C']=2;
	p['D']=3,p['E']=3,p['F']=3;
	p['G']=4,p['H']=4,p['I']=4;
	p['J']=5,p['K']=5,p['L']=5;
	p['M']=6,p['N']=6,p['O']=6;
	p['P']=7,p['Q']=7,p['R']=7,p['S']=7;
	p['T']=8,p['U']=8,p['V']=8;
	p['W']=9,p['X']=9,p['Y']=9,p['Z']=9;
	string a;
	cin>>a;
	for(int i=0;i<a.size();i++)
		ans+=(p[a[i]]+1);
	printf("%d\n",ans);
	return 0;
}

SUME

最暴力也是思考起來最簡單的辦法。

把所有方程(左下或右上的三角形),得到的和是\((n-1)(a_1+a_2...+a_n)\),可以計算出\((a_1+a_2...+a_n)\)的值。

然後對於\(a_i\),把和它有關的方程加起來,得到\(a_i+a_1+a_i+a_2...+a_i+a_{i-1}+a_i+a_{i+1}...+a_i+a_n\),即\((n-1)a_1+a_2+a_3...+a_n\),減去一個\((a_1+a_2...a_n)\),就可以計算出\((n-2)a_i\),除以\((n-2)\)即為答案。

不要問為什麼是\(O(n^2)\)的,輸入都是\(O(n^2)\)

的,時間複雜度啥的就無所謂了(bushi)。

最後,注意開longlong(血淚的教訓)

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[1010][1010];
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
signed main()
{
	int n,c=0;
	scanf("%lld",&n);
	if(n==2)
	{
		puts("1 1");
		return 0;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			a[i][j]=read();
	for(int i=2;i<=n;i++)
		for(int j=1;j<i;j++)
			c+=a[i][j];
	c/=(n-1);
	for(int k=1;k<=n;k++)
	{
		int cnt=0,ans=n-1;
		for(int j=1;j<=n;j++)
			cnt+=a[k][j];
		printf("%lld ",(cnt-c)/(n-2));
	}
	puts("");
	return 0;
} 

DBORI

首先想到\(O(n^2)\)處理處任意兩個元素的和值。

然後可以考慮用一個數組\(n[k]\)表示\(k\)是否能夠由兩個元素相加得到。由於有個位置之前的限制,所以記錄\(n[k]=i\)的意義是,\(k\)能夠由\(a[i]\)和一個 \(a[j](1\leq j\leq i)\)相加得到。

由於有正負,所以分段儲存就行了。

處理和判斷可以同時進行。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[20010];
int f[20010];
int nz[600010];
int nf[600010];
signed main()
{
	int n;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		for(int j=1;j<=i;j++)
		{
			int k=a[i]+a[j];
			if(k>=0&&!nz[k])nz[k]=i;
			else if(k<0&&!nf[-k])nf[-k]=i;
			int p=(a[i]-a[j]>=0)?nz[a[i]-a[j]]:nf[a[j]-a[i]];
			if(p&&p<i&&j!=i)f[i]=1;
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		ans+=f[i];
	printf("%lld\n",ans);
	return 0;
}

BUREK

容易發現能切割一個三角形的線就是在三角形橫座標覆蓋範圍內的或者是縱座標覆蓋範圍內的。

那麼容易得到一個三角形橫縱座標的極差,給範圍內除端點外的點加一,查詢的時候直接輸出就可以了。

發現會超時,於是上個基礎資料結構搞一搞就好了。

#include<bits/stdc++.h>
using namespace std;
inline int lowbit(int x)
{
	return x&-x;
}
int c[2][5000010];
const int MX=2e6+10;
const int ADD=1;
inline void adde(int x,int v,int k)
{
	for(int i=x;i<=MX;i+=lowbit(i))
		c[k][i]+=v;
}
inline void add(int x,int y,int v,int k)
{
	adde(x,v,k);
	adde(y+1,-v,k);
}
inline int ask(int x,int k)
{
	int cnt=0;
	for(int i=x;i;i-=lowbit(i))
		cnt+=c[k][i];
	return cnt;
}
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int a[6];
int main()
{
	int n,m;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		for(int k=0;k<6;k++)
		{
			a[k]=read();
			a[k]+=ADD;
		}
		//1x0y
		int q=min(min(a[0],a[2]),a[4]),w=max(max(a[0],a[2]),a[4]);
		int e=min(min(a[1],a[3]),a[5]),r=max(max(a[1],a[3]),a[5]);
		add(q+1,w-1,1,1);
		add(e+1,r-1,1,0);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		string xy,d;
		cin>>xy>>d;
		int c;
		c=read();
		printf("%d\n",ask(c+ADD,xy=="x"?1:0));
	}
	return 0;
}

剩下兩道題下次丕定補。