A题:A - Distinct Digits *800
题目大意:给你两个数,l和r,问你在l到r之间的数中存不存在每个数字都不相同的数,存在输出这个数,不存在输出-1
思路:暴力就完事
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],dp[maxn][5];
int main()
{
int a,b;
cin>>a>>b;
int to[11];
for(int i=a;i<=b;i++)
{
memset(to,0,sizeof(to));
int x=i;
while(x)
{
to[x%10]++;
if(to[x%10]>1)break;
x/=10;
}
if(x==0)
{
cout<<i<<endl;
return 0;
}
}
puts("-1");
return 0;
}
B题:B - Filling the Grid *1300
思路:每一列向下cj个连续黑块后一定有一个白块,每一行向右连续ri个黑块后一定有一个白块,把一定有的白块特别标记为-1,把黑块标记为1剩下的自由的块记为0,若存在答案,答案即为2的自由的块数次方对mod取模(因为自由块必是黑或白)。在标记过程中,碰到-1的块就是存在冲突,在标记-1块时,若待标记块已经被标黑则冲突,有冲突表示没有答案输出0.
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int mp[maxn][maxn];
const int mod=1e9+7;
int main()
{
int n,m,x,f=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x;
for(int j=1;j<=x;j++)mp[i][j]=1;
mp[i][x+1]=-1;
}
for(int j=1;j<=m;j++)
{
cin>>x;
for(int i=1;i<=x;i++)
{
if(mp[i][j]==-1)f=1;
mp[i][j]=1;
}
x++;
if(mp[x][j]==1)f=1;
else mp[x][j]=-1;
}
int sum=0;
if(f)
{
cout<<0<<endl;
return 0;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==0)sum++;
}
}
long long int ans=1;
for(int i=1;i<=sum;i++)
{
ans*=2;
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
C题:C - Primes and Multiplication 1600
数学题,思路:先把x的所有的质因子求出来。然后再用N除以它的每个质因子,例如1-N个数里面有N/2个数能被2整除,则这些数都存在2的一次的因子,剩下的N/2个数再/2表示有N/2/2个数存在2的2次这个因子。除到最后加起来表示1-N个数总共可以被2分解t次,(t=N/2+N/2/2+…),然后再处理下一个质因子。最后答案就是第一个质因子的t次方第二个质因子对应的t次方…
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int mod=1e9+7;
vector<int> e;
void prime(ll x)
{
ll tmp=x;
for(int i=2;i*i<=tmp;i++)
{
if(x%i==0)
{
e.push_back(i);
while(x%i==0 && x>0)
{
x/=i;
}
}
}
if(x>1)e.push_back(x);
}
ll qp(ll x,ll c)
{
ll ans=1;
ll tmp=x;
while(c)
{
if(c&1)
{
ans*=tmp;
ans%=mod;
}
tmp=tmp*tmp%mod;
c>>=1;
}
return ans;
}
int main()
{
ll x,n,ans=1;
cin>>x>>n;
prime(x);
for(int i=0;i<e.size();i++)
{
ll tmp=n,t=0;
while(tmp)
{
t+=tmp/e[i];
tmp/=e[i];
}
ans=ans*qp(e[i],t)%mod;
}
cout<<ans<<endl;
return 0;
}
D题:D - Complete Tripartite *1800
题目大意:给你一堆点一堆边,问你能不能分成一个三分图,每个部分的点都能连到另外连个部分的任意一个点
思路:正常思路是染色,先随便找一个点分到第一部分,然后把没有和它有直线连接的点都加到第二部分,然后再处理第二部分,第二部分随便找一个点,把没有和它直接相连的点全部弄成真的第二部分,剩下的如果不是第一部分的点加到第三部分,染完色再证明一下,每个点到其他部分每个点是不是有边连接,每一部分存不存在点与点之间有边的。
但是我在CF上发现有个很神奇的操作,用vector把和每个点有连线的点记录下来,然后每个不同的连线点集进行map赋值,如果给的图能按照要求分组,则不同的点集数量一定是三个,1的点部分对应2,3部分的点集是相同的,同理2对应1,3的点集也是相同的。如果正好三个点集,输出点对应的点集编号,不然输出-1
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
vector<int> e[maxn];
map<vector<int>,int> mp;
int main()
{
int n,m,x,y;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
int cnt=0;
for(int i=1;i<=n;i++)
{
if(e[i].size()==0)
{
puts("-1");
return 0;
}
sort(e[i].begin(),e[i].end());
if(!mp[e[i]])mp[e[i]]=++cnt;
}
if(cnt!=3)puts("-1");
else
for(int i=1;i<=n;i++)
{
cout<<mp[e[i]]<<" ";
}
return 0;
}